Version 5.3.10: Added support for Visual Studio 2013, fixed ErrorDetails line number issue in WindowsScriptEngine (Issue #24), added ScriptEngine.FormatCode and V8Runtime.FormatCode, disabled code formatting by default, fixed script access to nullable values (Issue #30), added ScriptEngine.GetStackTrace() (Issue #27), added V8Runtime.MaxStackUsage and V8ScriptEngine.MaxRuntimeStackUsage (Issue #26), fixed V8 root object marshaling crash when GlobalMembers is in effect, added tests for bug fixes and new APIs. Tested with V8 3.23.13.
This commit is contained in:
Родитель
b83270ae12
Коммит
133980c335
|
@ -18,6 +18,16 @@
|
|||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_BEFORE_TYPEOF_PARENTHESES/@EntryValue">False</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_WITHIN_SINGLE_LINE_ARRAY_INITIALIZER_BRACES/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_LINES/@EntryValue">False</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CLSID/@EntryIndexedValue">CLSID</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=COM/@EntryIndexedValue">COM</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DOM/@EntryIndexedValue">DOM</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GC/@EntryIndexedValue">GC</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=ID/@EntryIndexedValue">ID</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=JIT/@EntryIndexedValue">JIT</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=JS/@EntryIndexedValue">JS</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=URL/@EntryIndexedValue">URL</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=VB/@EntryIndexedValue">VB</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=VBS/@EntryIndexedValue">VBS</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
|
|
|
@ -69,16 +69,16 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define DEFINE_CALLBACK_MANAGER(NAME, TYPE) \
|
||||
DEFINE_CALLBACK_MANAGER_INTERNAL(NAME, TYPE, NullMutex)
|
||||
DEFINE_CALLBACK_MANAGER_INTERNAL(NAME, TYPE, NullMutex)
|
||||
|
||||
#define DEFINE_CONCURRENT_CALLBACK_MANAGER(NAME, TYPE) \
|
||||
DEFINE_CALLBACK_MANAGER_INTERNAL(NAME, TYPE, RecursiveMutex)
|
||||
DEFINE_CALLBACK_MANAGER_INTERNAL(NAME, TYPE, RecursiveMutex)
|
||||
|
||||
#define DEFINE_CALLBACK_MANAGER_INTERNAL(NAME, CALLBACK_TYPE, MUTEX_TYPE) \
|
||||
struct NAME##CallbackTraits: public CallbackTraits<NAME##CallbackTraits, CALLBACK_TYPE, MUTEX_TYPE> {};
|
||||
struct NAME##CallbackTraits: public CallbackTraits<NAME##CallbackTraits, CALLBACK_TYPE, MUTEX_TYPE> {};
|
||||
|
||||
#define CALLBACK_MANAGER(NAME) \
|
||||
CallbackManager<NAME##CallbackTraits>
|
||||
CallbackManager<NAME##CallbackTraits>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CallbackTraits
|
||||
|
|
|
@ -75,16 +75,16 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define DEFINE_CALLBACK_MANAGER(NAME, TYPE) \
|
||||
DEFINE_CALLBACK_MANAGER_INTERNAL(NAME, TYPE, NullMutex)
|
||||
DEFINE_CALLBACK_MANAGER_INTERNAL(NAME, TYPE, NullMutex)
|
||||
|
||||
#define DEFINE_CONCURRENT_CALLBACK_MANAGER(NAME, TYPE) \
|
||||
DEFINE_CALLBACK_MANAGER_INTERNAL(NAME, TYPE, RecursiveMutex)
|
||||
DEFINE_CALLBACK_MANAGER_INTERNAL(NAME, TYPE, RecursiveMutex)
|
||||
|
||||
#define DEFINE_CALLBACK_MANAGER_INTERNAL(NAME, CALLBACK_TYPE, MUTEX_TYPE) \
|
||||
struct NAME##CallbackTraits: public CallbackTraits<NAME##CallbackTraits, CALLBACK_TYPE, MUTEX_TYPE> {};
|
||||
struct NAME##CallbackTraits: public CallbackTraits<NAME##CallbackTraits, CALLBACK_TYPE, MUTEX_TYPE> {};
|
||||
|
||||
#define CALLBACK_MANAGER(NAME) \
|
||||
CallbackManager<NAME##CallbackTraits>
|
||||
CallbackManager<NAME##CallbackTraits>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CallbackTraits
|
||||
|
|
|
@ -63,5 +63,5 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#define CLEARSCRIPT_VERSION_STRING "5.3.9.0"
|
||||
#define CLEARSCRIPT_VERSION_COMMA_SEPARATED 5,3,9,0
|
||||
#define CLEARSCRIPT_VERSION_STRING "5.3.10.0"
|
||||
#define CLEARSCRIPT_VERSION_COMMA_SEPARATED 5,3,10,0
|
||||
|
|
|
@ -105,7 +105,7 @@ namespace Microsoft.ClearScript
|
|||
return result;
|
||||
}
|
||||
|
||||
if ((type == typeof(void)) || (type == typeof(object)))
|
||||
if ((type == typeof(void)) || (type == typeof(object)) || type.IsNullable())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -73,5 +73,5 @@ using System.Runtime.InteropServices;
|
|||
[assembly: InternalsVisibleTo("ClearScriptTest")]
|
||||
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: AssemblyVersion("5.3.9.0")]
|
||||
[assembly: AssemblyFileVersion("5.3.9.0")]
|
||||
[assembly: AssemblyVersion("5.3.10.0")]
|
||||
[assembly: AssemblyFileVersion("5.3.10.0")]
|
||||
|
|
|
@ -119,6 +119,17 @@ namespace Microsoft.ClearScript
|
|||
/// </remarks>
|
||||
public Type AccessContext { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables or disables script code formatting.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When this property is set to <c>true</c>, the script engine may format script code
|
||||
/// before executing or compiling it. This is intended to facilitate interactive debugging.
|
||||
/// The formatting operation currently includes stripping leading and trailing blank lines
|
||||
/// and removing global indentation.
|
||||
/// </remarks>
|
||||
public bool FormatCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value that controls whether script code is permitted to use reflection.
|
||||
/// </summary>
|
||||
|
@ -648,6 +659,16 @@ namespace Microsoft.ClearScript
|
|||
return Evaluate(documentName, discard, code, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string representation of the script call stack.
|
||||
/// </summary>
|
||||
/// <returns>The script call stack formatted as a string.</returns>
|
||||
/// <remarks>
|
||||
/// This method returns an empty string if the script engine is not executing script code.
|
||||
/// The stack trace text format is defined by the script engine.
|
||||
/// </remarks>
|
||||
public abstract string GetStackTrace();
|
||||
|
||||
/// <summary>
|
||||
/// Interrupts script execution and causes the script engine to throw an exception.
|
||||
/// </summary>
|
||||
|
|
|
@ -153,8 +153,18 @@ namespace Microsoft.ClearScript.Util
|
|||
return false;
|
||||
}
|
||||
|
||||
public static bool IsNullable(this Type type)
|
||||
{
|
||||
return type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(Nullable<>));
|
||||
}
|
||||
|
||||
public static bool IsAssignableFrom(this Type type, ref object value)
|
||||
{
|
||||
if (type.IsNullable())
|
||||
{
|
||||
return (value == null) || (Nullable.GetUnderlyingType(type).IsAssignableFrom(ref value));
|
||||
}
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
return !type.IsValueType;
|
||||
|
|
|
@ -22,13 +22,17 @@
|
|||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(VisualStudioVersion)'=='12.0'">
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(VisualStudioVersion)'=='11.0'">
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -22,13 +22,17 @@
|
|||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(VisualStudioVersion)'=='12.0'">
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(VisualStudioVersion)'=='11.0'">
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
@ -113,3 +114,16 @@ using namespace std;
|
|||
#ifndef DECLSPEC_NORETURN
|
||||
#define DECLSPEC_NORETURN __declspec(noreturn)
|
||||
#endif // !DECLSPEC_NORETURN
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define BEGIN_COMPOUND_MACRO \
|
||||
do \
|
||||
{
|
||||
|
||||
#define END_COMPOUND_MACRO \
|
||||
__pragma(warning(push)) \
|
||||
__pragma(warning(disable:4127)) \
|
||||
} \
|
||||
while (false) \
|
||||
__pragma(warning(pop))
|
||||
|
|
|
@ -220,7 +220,7 @@ V8Value HostObjectHelpers::Invoke(void* pvObject, const vector<V8Value>& args, b
|
|||
{
|
||||
try
|
||||
{
|
||||
auto argCount = (int)args.size();
|
||||
auto argCount = static_cast<int>(args.size());
|
||||
|
||||
auto exportedArgs = gcnew array<Object^>(argCount);
|
||||
for (auto index = 0; index < argCount; index++)
|
||||
|
@ -242,7 +242,7 @@ V8Value HostObjectHelpers::InvokeMethod(void* pvObject, const wchar_t* pName, co
|
|||
{
|
||||
try
|
||||
{
|
||||
auto argCount = (int)args.size();
|
||||
auto argCount = static_cast<int>(args.size());
|
||||
|
||||
auto exportedArgs = gcnew array<Object^>(argCount);
|
||||
for (auto index = 0; index < argCount; index++)
|
||||
|
|
|
@ -94,9 +94,9 @@ using namespace Microsoft::ClearScript::Util;
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define BEGIN_LOCK_SCOPE(OBJECT) \
|
||||
{ \
|
||||
msclr::lock t_Lock(OBJECT);
|
||||
{ \
|
||||
msclr::lock t_Lock(OBJECT);
|
||||
|
||||
#define END_LOCK_SCOPE \
|
||||
IGNORE_UNUSED(t_Lock); \
|
||||
}
|
||||
IGNORE_UNUSED(t_Lock); \
|
||||
}
|
||||
|
|
|
@ -153,9 +153,9 @@ private:
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define BEGIN_MUTEX_SCOPE(MUTEX) \
|
||||
{ \
|
||||
MutexLock<decltype(MUTEX)> t_MutexLock(MUTEX);
|
||||
{ \
|
||||
MutexLock<decltype(MUTEX)> t_MutexLock(MUTEX);
|
||||
|
||||
#define END_MUTEX_SCOPE \
|
||||
IGNORE_UNUSED(t_MutexLock); \
|
||||
}
|
||||
IGNORE_UNUSED(t_MutexLock); \
|
||||
}
|
||||
|
|
|
@ -120,12 +120,12 @@ private:
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define BEGIN_ADDREF_SCOPE \
|
||||
{ \
|
||||
AddRefScope t_AddRefScope(GetRefCount());
|
||||
{ \
|
||||
AddRefScope t_AddRefScope(GetRefCount());
|
||||
|
||||
#define END_ADDREF_SCOPE \
|
||||
IGNORE_UNUSED(t_AddRefScope); \
|
||||
}
|
||||
IGNORE_UNUSED(t_AddRefScope); \
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SharedPtr
|
||||
|
|
|
@ -71,6 +71,9 @@ public:
|
|||
|
||||
static V8Context* Create(const SharedPtr<V8Isolate>& spIsolate, const wchar_t* pName, bool enableDebugging, bool disableGlobalMembers, int debugPort);
|
||||
|
||||
virtual size_t GetMaxIsolateStackUsage() = 0;
|
||||
virtual void SetMaxIsolateStackUsage(size_t value) = 0;
|
||||
|
||||
typedef void LockCallbackT(void* pvArg);
|
||||
virtual void CallWithLock(LockCallbackT* pCallback, void* pvArg) = 0;
|
||||
|
||||
|
|
|
@ -152,50 +152,50 @@ static void* UnwrapHostObject(const FunctionCallbackInfo<T>& args)
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define BEGIN_ISOLATE_SCOPE \
|
||||
{ \
|
||||
V8IsolateImpl::Scope t_IsolateScope(m_spIsolateImpl);
|
||||
{ \
|
||||
V8IsolateImpl::Scope t_IsolateScope(m_spIsolateImpl);
|
||||
|
||||
#define END_ISOLATE_SCOPE \
|
||||
IGNORE_UNUSED(t_IsolateScope); \
|
||||
}
|
||||
IGNORE_UNUSED(t_IsolateScope); \
|
||||
}
|
||||
|
||||
#define BEGIN_CONTEXT_SCOPE \
|
||||
{ \
|
||||
Scope t_ContextScope(this);
|
||||
{ \
|
||||
Scope t_ContextScope(this);
|
||||
|
||||
#define END_CONTEXT_SCOPE \
|
||||
IGNORE_UNUSED(t_ContextScope); \
|
||||
}
|
||||
IGNORE_UNUSED(t_ContextScope); \
|
||||
}
|
||||
|
||||
#define BEGIN_CONTEXT_SCOPE_NOTHROW \
|
||||
{ \
|
||||
Context::Scope t_ContextScopeNoThrow(m_hContext);
|
||||
{ \
|
||||
Context::Scope t_ContextScopeNoThrow(m_hContext);
|
||||
|
||||
#define END_CONTEXT_SCOPE_NOTHROW \
|
||||
IGNORE_UNUSED(t_ContextScopeNoThrow); \
|
||||
}
|
||||
IGNORE_UNUSED(t_ContextScopeNoThrow); \
|
||||
}
|
||||
|
||||
#define BEGIN_VERIFY_SCOPE \
|
||||
{ \
|
||||
TryCatch t_TryCatch;
|
||||
#define BEGIN_EXECUTION_SCOPE \
|
||||
{ \
|
||||
V8IsolateImpl::ExecutionScope t_IsolateExecutionScope(m_spIsolateImpl); \
|
||||
TryCatch t_TryCatch;
|
||||
|
||||
#define END_VERIFY_SCOPE \
|
||||
IGNORE_UNUSED(t_TryCatch); \
|
||||
}
|
||||
#define END_EXECUTION_SCOPE \
|
||||
IGNORE_UNUSED(t_TryCatch); \
|
||||
IGNORE_UNUSED(t_IsolateExecutionScope); \
|
||||
}
|
||||
|
||||
#define VERIFY(RESULT) \
|
||||
Verify(t_TryCatch, RESULT)
|
||||
Verify(t_TryCatch, RESULT)
|
||||
|
||||
#define VERIFY_CHECKPOINT() \
|
||||
Verify(t_TryCatch)
|
||||
Verify(t_TryCatch)
|
||||
|
||||
#define CALLBACK_RETURN(RESULT) \
|
||||
do \
|
||||
{ \
|
||||
info.GetReturnValue().Set(RESULT); \
|
||||
return; \
|
||||
} \
|
||||
while (false)
|
||||
BEGIN_COMPOUND_MACRO \
|
||||
info.GetReturnValue().Set(RESULT); \
|
||||
return; \
|
||||
END_COMPOUND_MACRO
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
@ -255,6 +255,20 @@ V8ContextImpl::V8ContextImpl(V8IsolateImpl* pIsolateImpl, const wchar_t* pName,
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
size_t V8ContextImpl::GetMaxIsolateStackUsage()
|
||||
{
|
||||
return m_spIsolateImpl->GetMaxStackUsage();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::SetMaxIsolateStackUsage(size_t value)
|
||||
{
|
||||
m_spIsolateImpl->SetMaxStackUsage(value);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::CallWithLock(LockCallbackT* pCallback, void* pvArg)
|
||||
{
|
||||
VerifyNotOutOfMemory();
|
||||
|
@ -298,12 +312,12 @@ void V8ContextImpl::SetGlobalProperty(const wchar_t* pName, const V8Value& value
|
|||
V8Value V8ContextImpl::Execute(const wchar_t* pDocumentName, const wchar_t* pCode, bool /* discard */)
|
||||
{
|
||||
BEGIN_CONTEXT_SCOPE
|
||||
BEGIN_VERIFY_SCOPE
|
||||
BEGIN_EXECUTION_SCOPE
|
||||
|
||||
auto hScript = VERIFY(Script::Compile(String::New(pCode), String::New(pDocumentName)));
|
||||
return ExportValue(VERIFY(hScript->Run()));
|
||||
|
||||
END_VERIFY_SCOPE
|
||||
END_EXECUTION_SCOPE
|
||||
END_CONTEXT_SCOPE
|
||||
}
|
||||
|
||||
|
@ -312,12 +326,12 @@ V8Value V8ContextImpl::Execute(const wchar_t* pDocumentName, const wchar_t* pCod
|
|||
V8ScriptHolder* V8ContextImpl::Compile(const wchar_t* pDocumentName, const wchar_t* pCode)
|
||||
{
|
||||
BEGIN_CONTEXT_SCOPE
|
||||
BEGIN_VERIFY_SCOPE
|
||||
BEGIN_EXECUTION_SCOPE
|
||||
|
||||
auto hScript = VERIFY(Script::New(String::New(pCode), String::New(pDocumentName)));
|
||||
return new V8ScriptHolderImpl(m_spIsolateImpl, ::PtrFromScriptHandle(CreatePersistent(hScript)));
|
||||
|
||||
END_VERIFY_SCOPE
|
||||
END_EXECUTION_SCOPE
|
||||
END_CONTEXT_SCOPE
|
||||
}
|
||||
|
||||
|
@ -333,12 +347,12 @@ bool V8ContextImpl::CanExecute(V8ScriptHolder* pHolder)
|
|||
V8Value V8ContextImpl::Execute(V8ScriptHolder* pHolder)
|
||||
{
|
||||
BEGIN_CONTEXT_SCOPE
|
||||
BEGIN_VERIFY_SCOPE
|
||||
BEGIN_EXECUTION_SCOPE
|
||||
|
||||
auto hScript = ::ScriptHandleFromPtr(pHolder->GetScript());
|
||||
return ExportValue(VERIFY(hScript->Run()));
|
||||
|
||||
END_VERIFY_SCOPE
|
||||
END_EXECUTION_SCOPE
|
||||
END_CONTEXT_SCOPE
|
||||
}
|
||||
|
||||
|
@ -390,9 +404,11 @@ void V8ContextImpl::ReleaseV8Object(void* pvObject)
|
|||
V8Value V8ContextImpl::GetV8ObjectProperty(void* pvObject, const wchar_t* pName)
|
||||
{
|
||||
BEGIN_CONTEXT_SCOPE
|
||||
BEGIN_EXECUTION_SCOPE
|
||||
|
||||
return ExportValue(::ObjectHandleFromPtr(pvObject)->Get(String::New(pName)));
|
||||
|
||||
END_EXECUTION_SCOPE
|
||||
END_CONTEXT_SCOPE
|
||||
}
|
||||
|
||||
|
@ -401,9 +417,11 @@ V8Value V8ContextImpl::GetV8ObjectProperty(void* pvObject, const wchar_t* pName)
|
|||
void V8ContextImpl::SetV8ObjectProperty(void* pvObject, const wchar_t* pName, const V8Value& value)
|
||||
{
|
||||
BEGIN_CONTEXT_SCOPE
|
||||
BEGIN_EXECUTION_SCOPE
|
||||
|
||||
::ObjectHandleFromPtr(pvObject)->Set(String::New(pName), ImportValue(value));
|
||||
|
||||
END_EXECUTION_SCOPE
|
||||
END_CONTEXT_SCOPE
|
||||
}
|
||||
|
||||
|
@ -434,9 +452,11 @@ void V8ContextImpl::GetV8ObjectPropertyNames(void* pvObject, vector<wstring>& na
|
|||
V8Value V8ContextImpl::GetV8ObjectProperty(void* pvObject, int index)
|
||||
{
|
||||
BEGIN_CONTEXT_SCOPE
|
||||
BEGIN_EXECUTION_SCOPE
|
||||
|
||||
return ExportValue(::ObjectHandleFromPtr(pvObject)->Get(index));
|
||||
|
||||
END_EXECUTION_SCOPE
|
||||
END_CONTEXT_SCOPE
|
||||
}
|
||||
|
||||
|
@ -445,9 +465,11 @@ V8Value V8ContextImpl::GetV8ObjectProperty(void* pvObject, int index)
|
|||
void V8ContextImpl::SetV8ObjectProperty(void* pvObject, int index, const V8Value& value)
|
||||
{
|
||||
BEGIN_CONTEXT_SCOPE
|
||||
BEGIN_EXECUTION_SCOPE
|
||||
|
||||
::ObjectHandleFromPtr(pvObject)->Set(index, ImportValue(value));
|
||||
|
||||
END_EXECUTION_SCOPE
|
||||
END_CONTEXT_SCOPE
|
||||
}
|
||||
|
||||
|
@ -478,7 +500,7 @@ void V8ContextImpl::GetV8ObjectPropertyIndices(void* pvObject, vector<int>& indi
|
|||
V8Value V8ContextImpl::InvokeV8Object(void* pvObject, const vector<V8Value>& args, bool asConstructor)
|
||||
{
|
||||
BEGIN_CONTEXT_SCOPE
|
||||
BEGIN_VERIFY_SCOPE
|
||||
BEGIN_EXECUTION_SCOPE
|
||||
|
||||
auto hObject = ::ObjectHandleFromPtr(pvObject);
|
||||
|
||||
|
@ -487,12 +509,12 @@ V8Value V8ContextImpl::InvokeV8Object(void* pvObject, const vector<V8Value>& arg
|
|||
|
||||
if (asConstructor)
|
||||
{
|
||||
return ExportValue(VERIFY(hObject->CallAsConstructor((int)importedArgs.size(), importedArgs.data())));
|
||||
return ExportValue(VERIFY(hObject->CallAsConstructor(static_cast<int>(importedArgs.size()), importedArgs.data())));
|
||||
}
|
||||
|
||||
return ExportValue(VERIFY(hObject->CallAsFunction(hObject, (int)importedArgs.size(), importedArgs.data())));
|
||||
return ExportValue(VERIFY(hObject->CallAsFunction(hObject, static_cast<int>(importedArgs.size()), importedArgs.data())));
|
||||
|
||||
END_VERIFY_SCOPE
|
||||
END_EXECUTION_SCOPE
|
||||
END_CONTEXT_SCOPE
|
||||
}
|
||||
|
||||
|
@ -501,7 +523,7 @@ V8Value V8ContextImpl::InvokeV8Object(void* pvObject, const vector<V8Value>& arg
|
|||
V8Value V8ContextImpl::InvokeV8ObjectMethod(void* pvObject, const wchar_t* pName, const vector<V8Value>& args)
|
||||
{
|
||||
BEGIN_CONTEXT_SCOPE
|
||||
BEGIN_VERIFY_SCOPE
|
||||
BEGIN_EXECUTION_SCOPE
|
||||
|
||||
auto hObject = ::ObjectHandleFromPtr(pvObject);
|
||||
|
||||
|
@ -523,9 +545,9 @@ V8Value V8ContextImpl::InvokeV8ObjectMethod(void* pvObject, const wchar_t* pName
|
|||
ImportValues(args, importedArgs);
|
||||
|
||||
auto hMethod = VERIFY(hValue->ToObject());
|
||||
return ExportValue(VERIFY(hMethod->CallAsFunction(hObject, (int)importedArgs.size(), importedArgs.data())));
|
||||
return ExportValue(VERIFY(hMethod->CallAsFunction(hObject, static_cast<int>(importedArgs.size()), importedArgs.data())));
|
||||
|
||||
END_VERIFY_SCOPE
|
||||
END_EXECUTION_SCOPE
|
||||
END_CONTEXT_SCOPE
|
||||
}
|
||||
|
||||
|
@ -608,7 +630,7 @@ void V8ContextImpl::GetV8ObjectPropertyNames(Handle<Object> hObject, vector<wstr
|
|||
auto hNames = hObject->GetPropertyNames();
|
||||
if (!hNames.IsEmpty())
|
||||
{
|
||||
auto nameCount = (int)hNames->Length();
|
||||
auto nameCount = static_cast<int>(hNames->Length());
|
||||
|
||||
names.reserve(nameCount);
|
||||
for (auto index = 0; index < nameCount; index++)
|
||||
|
@ -616,7 +638,7 @@ void V8ContextImpl::GetV8ObjectPropertyNames(Handle<Object> hObject, vector<wstr
|
|||
auto hName = hNames->Get(index);
|
||||
if (!hName.IsEmpty())
|
||||
{
|
||||
wstring name(*String::Value(hName->ToString()));
|
||||
wstring name(*String::Value(hName));
|
||||
|
||||
int propertyIndex;
|
||||
if (!HostObjectHelpers::TryParseInt32(name.c_str(), propertyIndex))
|
||||
|
@ -637,7 +659,7 @@ void V8ContextImpl::GetV8ObjectPropertyIndices(Handle<Object> hObject, vector<in
|
|||
auto hNames = hObject->GetPropertyNames();
|
||||
if (!hNames.IsEmpty())
|
||||
{
|
||||
auto nameCount = (int)hNames->Length();
|
||||
auto nameCount = static_cast<int>(hNames->Length());
|
||||
|
||||
indices.reserve(nameCount);
|
||||
for (auto index = 0; index < nameCount; index++)
|
||||
|
@ -645,7 +667,7 @@ void V8ContextImpl::GetV8ObjectPropertyIndices(Handle<Object> hObject, vector<in
|
|||
auto hName = hNames->Get(index);
|
||||
if (!hName.IsEmpty())
|
||||
{
|
||||
wstring name(*String::Value(hName->ToString()));
|
||||
wstring name(*String::Value(hName));
|
||||
|
||||
int propertyIndex;
|
||||
if (HostObjectHelpers::TryParseInt32(name.c_str(), propertyIndex))
|
||||
|
@ -716,7 +738,7 @@ void V8ContextImpl::QueryGlobalProperty(Local<String> hName, const PropertyCallb
|
|||
if (pContextImpl != nullptr)
|
||||
{
|
||||
const vector<Persistent<Object>>& stack = pContextImpl->m_GlobalMembersStack;
|
||||
if (stack.size() > 0)
|
||||
if ((stack.size() > 0) && !hName->Equals(pContextImpl->m_hHostObjectCookieName))
|
||||
{
|
||||
for (auto it = stack.rbegin(); it != stack.rend(); it++)
|
||||
{
|
||||
|
@ -802,7 +824,7 @@ void V8ContextImpl::GetGlobalPropertyNames(const PropertyCallbackInfo<Array>& in
|
|||
|
||||
sort(names.begin(), names.end());
|
||||
auto newEnd = unique(names.begin(), names.end());
|
||||
auto nameCount = (int)(newEnd - names.begin());
|
||||
auto nameCount = static_cast<int>(newEnd - names.begin());
|
||||
|
||||
auto hImportedNames = Array::New(nameCount);
|
||||
for (auto index = 0; index < nameCount; index++)
|
||||
|
@ -951,7 +973,7 @@ void V8ContextImpl::GetGlobalPropertyIndices(const PropertyCallbackInfo<Array>&
|
|||
|
||||
sort(indices.begin(), indices.end());
|
||||
auto newEnd = unique(indices.begin(), indices.end());
|
||||
auto indexCount = (int)(newEnd - indices.begin());
|
||||
auto indexCount = static_cast<int>(newEnd - indices.begin());
|
||||
|
||||
auto hImportedIndices = Array::New(indexCount);
|
||||
for (auto index = 0; index < indexCount; index++)
|
||||
|
@ -1064,7 +1086,7 @@ void V8ContextImpl::GetHostObjectPropertyNames(const PropertyCallbackInfo<Array>
|
|||
{
|
||||
vector<wstring> names;
|
||||
HostObjectHelpers::GetPropertyNames(::UnwrapHostObject(info), names);
|
||||
auto nameCount = (int)names.size();
|
||||
auto nameCount = static_cast<int>(names.size());
|
||||
|
||||
auto hImportedNames = Array::New(nameCount);
|
||||
for (auto index = 0; index < nameCount; index++)
|
||||
|
@ -1126,7 +1148,7 @@ void V8ContextImpl::QueryHostObjectProperty(unsigned __int32 index, const Proper
|
|||
|
||||
for (auto it = indices.begin(); it < indices.end(); it++)
|
||||
{
|
||||
if (*it == (int)index)
|
||||
if (*it == static_cast<int>(index))
|
||||
{
|
||||
CALLBACK_RETURN(None);
|
||||
}
|
||||
|
@ -1164,7 +1186,7 @@ void V8ContextImpl::GetHostObjectPropertyIndices(const PropertyCallbackInfo<Arra
|
|||
{
|
||||
vector<int> indices;
|
||||
HostObjectHelpers::GetPropertyIndices(::UnwrapHostObject(info), indices);
|
||||
auto indexCount = (int)indices.size();
|
||||
auto indexCount = static_cast<int>(indices.size());
|
||||
|
||||
auto hImportedIndices = Array::New(indexCount);
|
||||
for (auto index = 0; index < indexCount; index++)
|
||||
|
@ -1378,7 +1400,7 @@ void V8ContextImpl::ImportValues(const vector<V8Value>& values, vector<Handle<Va
|
|||
{
|
||||
importedValues.clear();
|
||||
|
||||
auto valueCount = (int)values.size();
|
||||
auto valueCount = static_cast<int>(values.size());
|
||||
importedValues.reserve(valueCount);
|
||||
|
||||
for (auto index = 0; index < valueCount; index++)
|
||||
|
@ -1399,128 +1421,169 @@ void V8ContextImpl::Verify(const TryCatch& tryCatch)
|
|||
}
|
||||
|
||||
auto hException = tryCatch.Exception();
|
||||
wstring message = *String::Value(hException);
|
||||
wstring stackTrace;
|
||||
|
||||
auto hStackTrace = tryCatch.StackTrace();
|
||||
if (!hStackTrace.IsEmpty())
|
||||
wstring message;
|
||||
bool stackOverflow;
|
||||
|
||||
String::Value value(hException);
|
||||
if (value.length() > 0)
|
||||
{
|
||||
stackTrace = *String::Value(hStackTrace);
|
||||
message = *value;
|
||||
stackOverflow = (_wcsicmp(message.c_str(), L"RangeError: Maximum call stack size exceeded") == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// It is unclear why V8 sometimes generates blank exceptions, although it probably has
|
||||
// to do with memory pressure. It seems to happen only during stack overflow recovery.
|
||||
|
||||
message = L"Unknown error; potential stack overflow detected";
|
||||
stackOverflow = true;
|
||||
}
|
||||
|
||||
auto hMessage = tryCatch.Message();
|
||||
if (!hMessage.IsEmpty())
|
||||
#ifdef _DEBUG
|
||||
|
||||
if (stackOverflow)
|
||||
{
|
||||
if (message.length() < 1)
|
||||
// Stack overflow conditions require extreme care, as V8's behavior can be erratic
|
||||
// until the stack is unwound a bit. Much of the code below can trigger unexpected
|
||||
// fatal errors in this context, so it makes sense to bypass it. On the other hand,
|
||||
// losing error information is also undesirable, and the detection code above is far
|
||||
// from robust. These sanity checks are intended to mitigate this fragility.
|
||||
|
||||
_ASSERTE(hException->IsObject());
|
||||
_ASSERTE(wstring(*String::Value(hException->ToObject()->GetConstructorName())) == L"RangeError");
|
||||
}
|
||||
|
||||
#endif // _DEBUG
|
||||
|
||||
wstring stackTrace;
|
||||
V8Value innerException(V8Value::Undefined);
|
||||
|
||||
if (stackOverflow)
|
||||
{
|
||||
stackTrace = message;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto hStackTrace = tryCatch.StackTrace();
|
||||
if (!hStackTrace.IsEmpty())
|
||||
{
|
||||
message = *String::Value(hMessage->Get());
|
||||
stackTrace = *String::Value(hStackTrace);
|
||||
}
|
||||
|
||||
stackTrace = message;
|
||||
|
||||
auto hStackTrace = hMessage->GetStackTrace();
|
||||
int frameCount = !hStackTrace.IsEmpty() ? hStackTrace->GetFrameCount() : 0;
|
||||
|
||||
if (frameCount < 1)
|
||||
auto hMessage = tryCatch.Message();
|
||||
if (!hMessage.IsEmpty())
|
||||
{
|
||||
auto hScriptResourceName = hMessage->GetScriptResourceName();
|
||||
if (!hScriptResourceName.IsEmpty() && !hScriptResourceName->IsNull() && !hScriptResourceName->IsUndefined())
|
||||
if (message.length() < 1)
|
||||
{
|
||||
auto hScriptName = hScriptResourceName->ToString();
|
||||
if (!hScriptName.IsEmpty() && (hScriptName->Length() > 0))
|
||||
message = *String::Value(hMessage->Get());
|
||||
}
|
||||
|
||||
stackTrace = message;
|
||||
|
||||
auto hStackTrace = hMessage->GetStackTrace();
|
||||
int frameCount = !hStackTrace.IsEmpty() ? hStackTrace->GetFrameCount() : 0;
|
||||
|
||||
if (frameCount < 1)
|
||||
{
|
||||
auto hScriptResourceName = hMessage->GetScriptResourceName();
|
||||
if (!hScriptResourceName.IsEmpty() && !hScriptResourceName->IsNull() && !hScriptResourceName->IsUndefined())
|
||||
{
|
||||
stackTrace += L"\n at ";
|
||||
stackTrace += *String::Value(hScriptName);
|
||||
auto hScriptName = hScriptResourceName->ToString();
|
||||
if (!hScriptName.IsEmpty() && (hScriptName->Length() > 0))
|
||||
{
|
||||
stackTrace += L"\n at ";
|
||||
stackTrace += *String::Value(hScriptName);
|
||||
}
|
||||
else
|
||||
{
|
||||
stackTrace += L"\n at <anonymous>";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stackTrace += L"\n at <anonymous>";
|
||||
}
|
||||
|
||||
stackTrace += L':';
|
||||
stackTrace += to_wstring(hMessage->GetLineNumber());
|
||||
stackTrace += L':';
|
||||
stackTrace += to_wstring(hMessage->GetStartColumn() + 1);
|
||||
|
||||
auto hSourceLine = hMessage->GetSourceLine();
|
||||
if (!hSourceLine.IsEmpty() && (hSourceLine->Length() > 0))
|
||||
{
|
||||
stackTrace += L" -> ";
|
||||
stackTrace += *String::Value(hSourceLine);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stackTrace += L"\n at <anonymous>";
|
||||
}
|
||||
for (int index = 0; index < frameCount; index++)
|
||||
{
|
||||
auto hFrame = hStackTrace->GetFrame(index);
|
||||
stackTrace += L"\n at ";
|
||||
|
||||
stackTrace += L':';
|
||||
stackTrace += to_wstring(hMessage->GetLineNumber());
|
||||
stackTrace += L':';
|
||||
stackTrace += to_wstring(hMessage->GetStartColumn() + 1);
|
||||
auto hFunctionName = hFrame->GetFunctionName();
|
||||
if (!hFunctionName.IsEmpty() && (hFunctionName->Length() > 0))
|
||||
{
|
||||
if (hFrame->IsConstructor())
|
||||
{
|
||||
stackTrace += L"new ";
|
||||
}
|
||||
|
||||
auto hSourceLine = hMessage->GetSourceLine();
|
||||
if (!hSourceLine.IsEmpty() && (hSourceLine->Length() > 0))
|
||||
{
|
||||
stackTrace += L" -> ";
|
||||
stackTrace += *String::Value(hSourceLine);
|
||||
stackTrace += *String::Value(hFunctionName);
|
||||
stackTrace += L" (";
|
||||
}
|
||||
|
||||
auto hScriptName = hFrame->GetScriptName();
|
||||
if (!hScriptName.IsEmpty() && (hScriptName->Length() > 0))
|
||||
{
|
||||
stackTrace += *String::Value(hScriptName);
|
||||
}
|
||||
else
|
||||
{
|
||||
stackTrace += L"<anonymous>";
|
||||
}
|
||||
|
||||
stackTrace += L':';
|
||||
auto lineNumber = hFrame->GetLineNumber();
|
||||
if (lineNumber != Message::kNoLineNumberInfo)
|
||||
{
|
||||
stackTrace += to_wstring(lineNumber);
|
||||
}
|
||||
|
||||
stackTrace += L':';
|
||||
auto column = hFrame->GetColumn();
|
||||
if (column != Message::kNoColumnInfo)
|
||||
{
|
||||
stackTrace += to_wstring(column);
|
||||
}
|
||||
|
||||
if (!hFunctionName.IsEmpty() && (hFunctionName->Length() > 0))
|
||||
{
|
||||
stackTrace += L')';
|
||||
}
|
||||
|
||||
if (index == 0)
|
||||
{
|
||||
auto hSourceLine = hMessage->GetSourceLine();
|
||||
if (!hSourceLine.IsEmpty() && (hSourceLine->Length() > 0))
|
||||
{
|
||||
stackTrace += L" -> ";
|
||||
stackTrace += *String::Value(hSourceLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
if (hException->IsObject())
|
||||
{
|
||||
for (int index = 0; index < frameCount; index++)
|
||||
{
|
||||
auto hFrame = hStackTrace->GetFrame(index);
|
||||
stackTrace += L"\n at ";
|
||||
|
||||
auto hFunctionName = hFrame->GetFunctionName();
|
||||
if (!hFunctionName.IsEmpty() && (hFunctionName->Length() > 0))
|
||||
{
|
||||
if (hFrame->IsConstructor())
|
||||
{
|
||||
stackTrace += L"new ";
|
||||
}
|
||||
|
||||
stackTrace += *String::Value(hFunctionName);
|
||||
stackTrace += L" (";
|
||||
}
|
||||
|
||||
auto hScriptName = hFrame->GetScriptName();
|
||||
if (!hScriptName.IsEmpty() && (hScriptName->Length() > 0))
|
||||
{
|
||||
stackTrace += *String::Value(hScriptName);
|
||||
}
|
||||
else
|
||||
{
|
||||
stackTrace += L"<anonymous>";
|
||||
}
|
||||
|
||||
stackTrace += L':';
|
||||
auto lineNumber = hFrame->GetLineNumber();
|
||||
if (lineNumber != Message::kNoLineNumberInfo)
|
||||
{
|
||||
stackTrace += to_wstring(lineNumber);
|
||||
}
|
||||
|
||||
stackTrace += L':';
|
||||
auto column = hFrame->GetColumn();
|
||||
if (column != Message::kNoColumnInfo)
|
||||
{
|
||||
stackTrace += to_wstring(column);
|
||||
}
|
||||
|
||||
if (!hFunctionName.IsEmpty() && (hFunctionName->Length() > 0))
|
||||
{
|
||||
stackTrace += L')';
|
||||
}
|
||||
|
||||
if (index == 0)
|
||||
{
|
||||
auto hSourceLine = hMessage->GetSourceLine();
|
||||
if (!hSourceLine.IsEmpty() && (hSourceLine->Length() > 0))
|
||||
{
|
||||
stackTrace += L" -> ";
|
||||
stackTrace += *String::Value(hSourceLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
innerException = ExportValue(hException->ToObject()->Get(m_hInnerExceptionName));
|
||||
}
|
||||
}
|
||||
|
||||
V8Value innerException(V8Value::Undefined);
|
||||
if (hException->IsObject())
|
||||
{
|
||||
innerException = ExportValue(hException->ToObject()->Get(m_hInnerExceptionName));
|
||||
}
|
||||
|
||||
throw V8Exception(V8Exception::Type_General, m_Name.c_str(), message.c_str(), stackTrace.c_str(), innerException);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,6 +73,9 @@ public:
|
|||
|
||||
V8ContextImpl(V8IsolateImpl* pIsolateImpl, const wchar_t* pName, bool enableDebugging, bool disableGlobalMembers, int debugPort);
|
||||
|
||||
size_t GetMaxIsolateStackUsage();
|
||||
void SetMaxIsolateStackUsage(size_t value);
|
||||
|
||||
void CallWithLock(LockCallbackT* pCallback, void* pvArg);
|
||||
V8Value GetRootObject();
|
||||
void SetGlobalProperty(const wchar_t* pName, const V8Value& value, bool globalMembers);
|
||||
|
|
|
@ -94,6 +94,20 @@ namespace V8 {
|
|||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
UIntPtr V8ContextProxyImpl::MaxRuntimeStackUsage::get()
|
||||
{
|
||||
return (UIntPtr)GetContext()->GetMaxIsolateStackUsage();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
void V8ContextProxyImpl::MaxRuntimeStackUsage::set(UIntPtr value)
|
||||
{
|
||||
GetContext()->SetMaxIsolateStackUsage(static_cast<size_t>(value));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
void V8ContextProxyImpl::InvokeWithLock(Action^ gcAction)
|
||||
{
|
||||
try
|
||||
|
|
|
@ -75,6 +75,12 @@ namespace V8 {
|
|||
|
||||
V8ContextProxyImpl(V8IsolateProxy^ gcIsolateProxy, String^ gcName, Boolean enableDebugging, Boolean disableGlobalMembers, Int32 debugPort);
|
||||
|
||||
property UIntPtr MaxRuntimeStackUsage
|
||||
{
|
||||
virtual UIntPtr get() override;
|
||||
virtual void set(UIntPtr value) override;
|
||||
}
|
||||
|
||||
virtual void InvokeWithLock(Action^ gcAction) override;
|
||||
virtual Object^ GetRootItem() override;
|
||||
virtual void AddGlobalItem(String^ gcName, Object^ gcItem, Boolean globalMembers) override;
|
||||
|
|
|
@ -71,6 +71,9 @@ public:
|
|||
|
||||
static V8Isolate* Create(const wchar_t* pName, const V8IsolateConstraints* pConstraints, bool enableDebugging, int debugPort);
|
||||
|
||||
virtual size_t GetMaxStackUsage() = 0;
|
||||
virtual void SetMaxStackUsage(size_t value) = 0;
|
||||
|
||||
virtual V8ScriptHolder* Compile(const wchar_t* pDocumentName, const wchar_t* pCode) = 0;
|
||||
virtual void GetHeapInfo(V8IsolateHeapInfo& heapInfo) = 0;
|
||||
virtual void CollectGarbage(bool exhaustive) = 0;
|
||||
|
|
|
@ -82,20 +82,20 @@ static Persistent<Script> ScriptHandleFromPtr(void* pvScript)
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define BEGIN_ISOLATE_ENTRY_SCOPE \
|
||||
{ \
|
||||
Isolate::Scope t_IsolateEntryScope(m_pIsolate);
|
||||
{ \
|
||||
Isolate::Scope t_IsolateEntryScope(m_pIsolate);
|
||||
|
||||
#define END_ISOLATE_ENTRY_SCOPE \
|
||||
IGNORE_UNUSED(t_IsolateEntryScope); \
|
||||
}
|
||||
IGNORE_UNUSED(t_IsolateEntryScope); \
|
||||
}
|
||||
|
||||
#define BEGIN_ISOLATE_SCOPE \
|
||||
{ \
|
||||
Scope t_IsolateScope(this);
|
||||
{ \
|
||||
Scope t_IsolateScope(this);
|
||||
|
||||
#define END_ISOLATE_SCOPE \
|
||||
IGNORE_UNUSED(t_IsolateScope); \
|
||||
}
|
||||
IGNORE_UNUSED(t_IsolateScope); \
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
@ -103,10 +103,18 @@ DEFINE_CONCURRENT_CALLBACK_MANAGER(DebugMessageDispatcher, void())
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
V8IsolateImpl::V8IsolateImpl(const wchar_t* pName, const V8IsolateConstraints* pConstraints, bool enableDebugging, int debugPort):
|
||||
static const size_t s_StackBreathingRoom = static_cast<size_t>(16 * 1024);
|
||||
static size_t* const s_pMinStackLimit = reinterpret_cast<size_t*>(sizeof(size_t));
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
V8IsolateImpl::V8IsolateImpl(const wchar_t* pName, const V8IsolateConstraints* pConstraints, bool enableDebugging, int debugPort) :
|
||||
m_pIsolate(Isolate::New()),
|
||||
m_DebuggingEnabled(false),
|
||||
m_DebugMessageDispatchCount(0),
|
||||
m_MaxStackUsage(0),
|
||||
m_ExecutionLevel(0),
|
||||
m_pStackLimit(nullptr),
|
||||
m_IsOutOfMemory(false)
|
||||
{
|
||||
BEGIN_ADDREF_SCOPE
|
||||
|
@ -126,7 +134,7 @@ V8IsolateImpl::V8IsolateImpl(const wchar_t* pName, const V8IsolateConstraints* p
|
|||
constraints.set_max_young_space_size(pConstraints->GetMaxYoungSpaceSize());
|
||||
constraints.set_max_old_space_size(pConstraints->GetMaxOldSpaceSize());
|
||||
constraints.set_max_executable_size(pConstraints->GetMaxExecutableSize());
|
||||
ASSERT_EVAL(SetResourceConstraints(&constraints));
|
||||
ASSERT_EVAL(SetResourceConstraints(m_pIsolate, &constraints));
|
||||
}
|
||||
|
||||
END_ISOLATE_ENTRY_SCOPE
|
||||
|
@ -232,6 +240,20 @@ void V8IsolateImpl::DisableDebugging()
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
size_t V8IsolateImpl::GetMaxStackUsage()
|
||||
{
|
||||
return m_MaxStackUsage;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8IsolateImpl::SetMaxStackUsage(size_t value)
|
||||
{
|
||||
m_MaxStackUsage = value;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
V8ScriptHolder* V8IsolateImpl::Compile(const wchar_t* pDocumentName, const wchar_t* pCode)
|
||||
{
|
||||
BEGIN_ISOLATE_SCOPE
|
||||
|
@ -348,3 +370,72 @@ void V8IsolateImpl::ProcessDebugMessages()
|
|||
|
||||
END_ISOLATE_SCOPE
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8IsolateImpl::EnterExecutionScope(size_t* pStackMarker)
|
||||
{
|
||||
_ASSERTE(m_pIsolate == Isolate::GetCurrent());
|
||||
_ASSERTE(Locker::IsLocked(m_pIsolate));
|
||||
|
||||
if (m_ExecutionLevel == 0)
|
||||
{
|
||||
// entering top-level execution scope
|
||||
_ASSERTE(m_pStackLimit == nullptr);
|
||||
|
||||
// is a stack usage limit specified?
|
||||
size_t maxStackUsage = m_MaxStackUsage;
|
||||
if (maxStackUsage > 0)
|
||||
{
|
||||
// yes; ensure minimum breathing room
|
||||
maxStackUsage = max(maxStackUsage, s_StackBreathingRoom);
|
||||
|
||||
// calculate stack address limit
|
||||
size_t* pStackLimit = pStackMarker - (maxStackUsage / sizeof(size_t));
|
||||
if ((pStackLimit < s_pMinStackLimit) || (pStackLimit > pStackMarker))
|
||||
{
|
||||
// underflow; use minimum non-null stack address
|
||||
pStackLimit = s_pMinStackLimit;
|
||||
}
|
||||
else
|
||||
{
|
||||
// check stack address limit sanity
|
||||
_ASSERTE((pStackMarker - pStackLimit) >= (s_StackBreathingRoom / sizeof(size_t)));
|
||||
}
|
||||
|
||||
// set and record stack address limit
|
||||
ResourceConstraints constraints;
|
||||
constraints.set_stack_limit(reinterpret_cast<uint32_t*>(pStackLimit));
|
||||
ASSERT_EVAL(SetResourceConstraints(m_pIsolate, &constraints));
|
||||
m_pStackLimit = pStackLimit;
|
||||
}
|
||||
}
|
||||
else if ((m_pStackLimit != nullptr) && (pStackMarker < m_pStackLimit))
|
||||
{
|
||||
// stack usage limit exceeded (host-side detection)
|
||||
throw V8Exception(V8Exception::Type_General, m_Name.c_str(), L"The V8 runtime has exceeded its stack usage limit", nullptr, V8Value(V8Value::Undefined));
|
||||
}
|
||||
|
||||
m_ExecutionLevel++;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8IsolateImpl::ExitExecutionScope()
|
||||
{
|
||||
_ASSERTE(m_pIsolate == Isolate::GetCurrent());
|
||||
_ASSERTE(Locker::IsLocked(m_pIsolate));
|
||||
|
||||
if (--m_ExecutionLevel == 0)
|
||||
{
|
||||
// exiting top-level execution scope
|
||||
if (m_pStackLimit != nullptr)
|
||||
{
|
||||
// V8 has no API for removing a stack address limit
|
||||
ResourceConstraints constraints;
|
||||
constraints.set_stack_limit(reinterpret_cast<uint32_t*>(s_pMinStackLimit));
|
||||
ASSERT_EVAL(SetResourceConstraints(m_pIsolate, &constraints));
|
||||
m_pStackLimit = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,6 +98,29 @@ public:
|
|||
HandleScope m_HandleScope;
|
||||
};
|
||||
|
||||
class ExecutionScope
|
||||
{
|
||||
PROHIBIT_COPY(ExecutionScope)
|
||||
PROHIBIT_HEAP(ExecutionScope)
|
||||
|
||||
public:
|
||||
|
||||
explicit ExecutionScope(V8IsolateImpl* pIsolateImpl):
|
||||
m_pIsolateImpl(pIsolateImpl)
|
||||
{
|
||||
m_pIsolateImpl->EnterExecutionScope(reinterpret_cast<size_t*>(&pIsolateImpl));
|
||||
}
|
||||
|
||||
~ExecutionScope()
|
||||
{
|
||||
m_pIsolateImpl->ExitExecutionScope();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
V8IsolateImpl* m_pIsolateImpl;
|
||||
};
|
||||
|
||||
V8IsolateImpl(const wchar_t* pName, const V8IsolateConstraints* pConstraints, bool enableDebugging, int debugPort);
|
||||
|
||||
Local<Context> CreateContext(ExtensionConfiguration* pExtensionConfiguation = nullptr, Handle<ObjectTemplate> hGlobalTemplate = Handle<ObjectTemplate>(), Handle<Value> hGlobalObject = Handle<Value>())
|
||||
|
@ -187,6 +210,9 @@ public:
|
|||
void EnableDebugging(int debugPort);
|
||||
void DisableDebugging();
|
||||
|
||||
size_t GetMaxStackUsage();
|
||||
void SetMaxStackUsage(size_t value);
|
||||
|
||||
V8ScriptHolder* Compile(const wchar_t* pDocumentName, const wchar_t* pCode);
|
||||
void GetHeapInfo(V8IsolateHeapInfo& heapInfo);
|
||||
void CollectGarbage(bool exhaustive);
|
||||
|
@ -203,6 +229,9 @@ private:
|
|||
void DispatchDebugMessages();
|
||||
void ProcessDebugMessages();
|
||||
|
||||
void EnterExecutionScope(size_t* pStackMarker);
|
||||
void ExitExecutionScope();
|
||||
|
||||
wstring m_Name;
|
||||
Isolate* m_pIsolate;
|
||||
list<V8ContextImpl*> m_ContextPtrs;
|
||||
|
@ -212,5 +241,9 @@ private:
|
|||
Debug::DebugMessageDispatchHandler m_pDebugMessageDispatcher;
|
||||
atomic<size_t> m_DebugMessageDispatchCount;
|
||||
|
||||
atomic<size_t> m_MaxStackUsage;
|
||||
size_t m_ExecutionLevel;
|
||||
size_t* m_pStackLimit;
|
||||
|
||||
atomic<bool> m_IsOutOfMemory;
|
||||
};
|
||||
|
|
|
@ -93,6 +93,20 @@ namespace V8 {
|
|||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
UIntPtr V8IsolateProxyImpl::MaxStackUsage::get()
|
||||
{
|
||||
return (UIntPtr)GetIsolate()->GetMaxStackUsage();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
void V8IsolateProxyImpl::MaxStackUsage::set(UIntPtr value)
|
||||
{
|
||||
GetIsolate()->SetMaxStackUsage(static_cast<size_t>(value));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
V8Script^ V8IsolateProxyImpl::Compile(String^ gcDocumentName, String^ gcCode)
|
||||
{
|
||||
try
|
||||
|
|
|
@ -75,6 +75,12 @@ namespace V8 {
|
|||
|
||||
V8IsolateProxyImpl(String^ gcName, V8RuntimeConstraints^ gcConstraints, Boolean enableDebugging, Int32 debugPort);
|
||||
|
||||
property UIntPtr MaxStackUsage
|
||||
{
|
||||
virtual UIntPtr get() override;
|
||||
virtual void set(UIntPtr value) override;
|
||||
}
|
||||
|
||||
virtual V8Script^ Compile(String^ gcDocumentName, String^ gcCode) override;
|
||||
virtual V8RuntimeHeapInfo^ GetHeapInfo() override;
|
||||
virtual void CollectGarbage(bool exhaustive) override;
|
||||
|
|
|
@ -125,7 +125,7 @@ namespace V8 {
|
|||
{
|
||||
vector<wstring> names;
|
||||
V8ObjectHelpers::GetPropertyNames(GetHolder(), names);
|
||||
auto nameCount = (int)names.size();
|
||||
auto nameCount = static_cast<int>(names.size());
|
||||
|
||||
auto gcNames = gcnew array<String^>(nameCount);
|
||||
for (auto index = 0; index < nameCount; index++)
|
||||
|
@ -191,7 +191,7 @@ namespace V8 {
|
|||
{
|
||||
vector<int> indices;
|
||||
V8ObjectHelpers::GetPropertyIndices(GetHolder(), indices);
|
||||
auto indexCount = (int)indices.size();
|
||||
auto indexCount = static_cast<int>(indices.size());
|
||||
|
||||
auto gcIndices = gcnew array<int>(indexCount);
|
||||
for (auto index = 0; index < indexCount; index++)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
Index: src/utils.h
|
||||
===================================================================
|
||||
--- src/utils.h (revision 17421)
|
||||
--- src/utils.h (revision 18109)
|
||||
+++ src/utils.h (working copy)
|
||||
@@ -109,7 +109,7 @@
|
||||
// These are kind of 2's complement reciprocal of the divisors.
|
||||
|
@ -13,9 +13,9 @@ Index: src/utils.h
|
|||
// lithium-codegen-arm.cc : LCodeGen::TryEmitSignedIntegerDivisionByConstant().
|
||||
Index: tools/gyp/v8.gyp
|
||||
===================================================================
|
||||
--- tools/gyp/v8.gyp (revision 17421)
|
||||
--- tools/gyp/v8.gyp (revision 18109)
|
||||
+++ tools/gyp/v8.gyp (working copy)
|
||||
@@ -33,6 +33,7 @@
|
||||
@@ -34,6 +34,7 @@
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'v8',
|
||||
|
|
|
@ -70,6 +70,8 @@ namespace Microsoft.ClearScript.V8
|
|||
return CreateImpl<V8ContextProxy>(isolateProxy, name, enableDebugging, disableGlobalMembers, debugPort);
|
||||
}
|
||||
|
||||
public abstract UIntPtr MaxRuntimeStackUsage { get; set; }
|
||||
|
||||
public abstract void InvokeWithLock(Action action);
|
||||
|
||||
public abstract object GetRootItem();
|
||||
|
|
|
@ -59,6 +59,8 @@
|
|||
// fitness for a particular purpose and non-infringement.
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.ClearScript.V8
|
||||
{
|
||||
internal abstract class V8IsolateProxy : V8Proxy
|
||||
|
@ -68,6 +70,8 @@ namespace Microsoft.ClearScript.V8
|
|||
return CreateImpl<V8IsolateProxy>(name, constraints, enableDebugging, debugPort);
|
||||
}
|
||||
|
||||
public abstract UIntPtr MaxStackUsage { get; set; }
|
||||
|
||||
public abstract V8Script Compile(string documentName, string code);
|
||||
|
||||
public abstract V8RuntimeHeapInfo GetHeapInfo();
|
||||
|
|
|
@ -216,6 +216,44 @@ namespace Microsoft.ClearScript.V8
|
|||
get { return name; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables or disables script code formatting.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When this property is set to <c>true</c>, the V8 runtime may format script code before
|
||||
/// executing or compiling it. This is intended to facilitate interactive debugging. The
|
||||
/// formatting operation currently includes stripping leading and trailing blank lines and
|
||||
/// removing global indentation.
|
||||
/// </remarks>
|
||||
public bool FormatCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum amount by which the stack is permitted to grow during script execution.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This property is specified in bytes. When it is set to the default value, no stack
|
||||
/// usage limit is enforced, and unchecked recursion or other stack usage may lead to
|
||||
/// unrecoverable errors and process termination.
|
||||
/// <para>
|
||||
/// Note that the V8 runtime does not monitor stack usage while a host call is in progress.
|
||||
/// Monitoring is resumed when control returns to the runtime.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public UIntPtr MaxStackUsage
|
||||
{
|
||||
get
|
||||
{
|
||||
VerifyNotDisposed();
|
||||
return proxy.MaxStackUsage;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
VerifyNotDisposed();
|
||||
proxy.MaxStackUsage = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new V8 script engine instance.
|
||||
/// </summary>
|
||||
|
@ -321,7 +359,7 @@ namespace Microsoft.ClearScript.V8
|
|||
public V8ScriptEngine CreateScriptEngine(string engineName, V8ScriptEngineFlags flags, int debugPort)
|
||||
{
|
||||
VerifyNotDisposed();
|
||||
return new V8ScriptEngine(this, engineName, null, flags, debugPort);
|
||||
return new V8ScriptEngine(this, engineName, null, flags, debugPort) { FormatCode = FormatCode };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -344,7 +382,7 @@ namespace Microsoft.ClearScript.V8
|
|||
{
|
||||
VerifyNotDisposed();
|
||||
var uniqueName = name + ":" + documentNameManager.GetUniqueName(documentName, "Script Document");
|
||||
return proxy.Compile(uniqueName, MiscHelpers.FormatCode(code));
|
||||
return proxy.Compile(uniqueName, FormatCode ? MiscHelpers.FormatCode(code) : code);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Microsoft.ClearScript.Util;
|
||||
using Microsoft.ClearScript.Windows;
|
||||
|
@ -307,6 +308,16 @@ namespace Microsoft.ClearScript.V8
|
|||
throw new Error('Function expected');
|
||||
}
|
||||
return method.apply(target, convertArgs(args));
|
||||
},
|
||||
|
||||
getStackTrace: function () {
|
||||
try {
|
||||
throw new Error('[stack trace]');
|
||||
}
|
||||
catch (exception) {
|
||||
return exception.stack;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
@ -321,6 +332,33 @@ namespace Microsoft.ClearScript.V8
|
|||
|
||||
#region public members
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum amount by which the V8 runtime is permitted to grow the stack during script execution.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This property is specified in bytes. When it is set to the default value, no stack
|
||||
/// usage limit is enforced, and unchecked recursion or other stack usage may lead to
|
||||
/// unrecoverable errors and process termination.
|
||||
/// <para>
|
||||
/// Note that the V8 runtime does not monitor stack usage while a host call is in progress.
|
||||
/// Monitoring is resumed when control returns to the runtime.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public UIntPtr MaxRuntimeStackUsage
|
||||
{
|
||||
get
|
||||
{
|
||||
VerifyNotDisposed();
|
||||
return proxy.MaxRuntimeStackUsage;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
VerifyNotDisposed();
|
||||
proxy.MaxRuntimeStackUsage = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a compiled script.
|
||||
/// </summary>
|
||||
|
@ -344,7 +382,7 @@ namespace Microsoft.ClearScript.V8
|
|||
return ScriptInvoke(() =>
|
||||
{
|
||||
var uniqueName = documentNameManager.GetUniqueName(documentName, "Script Document");
|
||||
return proxy.Compile(uniqueName, MiscHelpers.FormatCode(code));
|
||||
return proxy.Compile(uniqueName, FormatCode ? MiscHelpers.FormatCode(code) : code);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -473,6 +511,21 @@ namespace Microsoft.ClearScript.V8
|
|||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string representation of the script call stack.
|
||||
/// </summary>
|
||||
/// <returns>The script call stack formatted as a string.</returns>
|
||||
/// <remarks>
|
||||
/// This method returns an empty string if the script engine is not executing script code.
|
||||
/// The stack trace text format is defined by the script engine.
|
||||
/// </remarks>
|
||||
public override string GetStackTrace()
|
||||
{
|
||||
string stackTrace = Script.EngineInternal.getStackTrace();
|
||||
var lines = stackTrace.Split('\n');
|
||||
return string.Join("\n", lines.Skip(2));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interrupts script execution and causes the script engine to throw an exception.
|
||||
/// </summary>
|
||||
|
@ -630,7 +683,7 @@ namespace Microsoft.ClearScript.V8
|
|||
stateObjects[0] = new WeakReference(this);
|
||||
stateObjects[1] = timer;
|
||||
timer.Change(continuationInterval, Timeout.Infinite);
|
||||
return proxy.Execute(uniqueName, MiscHelpers.FormatCode(code), discard);
|
||||
return proxy.Execute(uniqueName, FormatCode ? MiscHelpers.FormatCode(code) : code, discard);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ namespace Microsoft.ClearScript.Windows
|
|||
{
|
||||
try
|
||||
{
|
||||
var stackTrace = GetStackTrace();
|
||||
var stackTrace = engine.GetStackTraceInternal();
|
||||
if (!string.IsNullOrWhiteSpace(stackTrace))
|
||||
{
|
||||
return message + "\n" + stackTrace;
|
||||
|
@ -109,75 +109,6 @@ namespace Microsoft.ClearScript.Windows
|
|||
return message;
|
||||
}
|
||||
|
||||
private string GetStackTrace()
|
||||
{
|
||||
var stackTrace = string.Empty;
|
||||
|
||||
IEnumDebugStackFrames enumFrames;
|
||||
engine.activeScript.EnumStackFrames(out enumFrames);
|
||||
|
||||
while (true)
|
||||
{
|
||||
DebugStackFrameDescriptor descriptor;
|
||||
uint countFetched;
|
||||
enumFrames.Next(1, out descriptor, out countFetched);
|
||||
if (countFetched < 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string description;
|
||||
descriptor.Frame.GetDescriptionString(true, out description);
|
||||
|
||||
IDebugCodeContext codeContext;
|
||||
descriptor.Frame.GetCodeContext(out codeContext);
|
||||
|
||||
IDebugDocumentContext documentContext;
|
||||
codeContext.GetDocumentContext(out documentContext);
|
||||
|
||||
IDebugDocument document;
|
||||
documentContext.GetDocument(out document);
|
||||
var documentText = (IDebugDocumentText)document;
|
||||
|
||||
string documentName;
|
||||
document.GetName(DocumentNameType.Title, out documentName);
|
||||
|
||||
uint position;
|
||||
uint length;
|
||||
documentText.GetPositionOfContext(documentContext, out position, out length);
|
||||
|
||||
var pBuffer = Marshal.AllocCoTaskMem((int)(sizeof(char) * length));
|
||||
try
|
||||
{
|
||||
uint lengthReturned = 0;
|
||||
documentText.GetText(position, pBuffer, IntPtr.Zero, ref lengthReturned, length);
|
||||
var codeLine = Marshal.PtrToStringUni(pBuffer, (int)lengthReturned);
|
||||
|
||||
uint lineNumber;
|
||||
uint offsetInLine;
|
||||
documentText.GetLineOfPosition(position, out lineNumber, out offsetInLine);
|
||||
|
||||
stackTrace += MiscHelpers.FormatInvariant(" at {0} ({1}:{2}:{3}) -> {4}\n", description, documentName, lineNumber, offsetInLine, codeLine);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeCoTaskMem(pBuffer);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (descriptor.FinalObject != null)
|
||||
{
|
||||
Marshal.ReleaseComObject(descriptor.FinalObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stackTrace;
|
||||
}
|
||||
|
||||
private string GetErrorLocation(object error)
|
||||
{
|
||||
var scriptError = error as IActiveScriptError;
|
||||
|
@ -198,7 +129,7 @@ namespace Microsoft.ClearScript.Windows
|
|||
if (lineNumber > 0)
|
||||
{
|
||||
uint linePosition;
|
||||
document.GetPositionOfLine(--lineNumber, out linePosition);
|
||||
document.GetPositionOfLine(lineNumber, out linePosition);
|
||||
position = (int)linePosition + offsetInLine;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -185,7 +185,7 @@ namespace Microsoft.ClearScript.Windows
|
|||
|
||||
private void Parse(string documentName, string code, ScriptTextFlags flags, IntPtr pVarResult, out EXCEPINFO excepInfo, bool discard)
|
||||
{
|
||||
var formattedCode = MiscHelpers.FormatCode(code);
|
||||
var formattedCode = FormatCode ? MiscHelpers.FormatCode(code) : code;
|
||||
|
||||
DebugDocument debugDocument;
|
||||
var sourceContext = CreateDebugDocument(documentName, formattedCode, discard, out debugDocument);
|
||||
|
@ -227,6 +227,82 @@ namespace Microsoft.ClearScript.Windows
|
|||
return sourceContext;
|
||||
}
|
||||
|
||||
private string GetStackTraceInternal()
|
||||
{
|
||||
Debug.Assert(engineFlags.HasFlag(WindowsScriptEngineFlags.EnableDebugging));
|
||||
var stackTrace = string.Empty;
|
||||
|
||||
IEnumDebugStackFrames enumFrames;
|
||||
activeScript.EnumStackFrames(out enumFrames);
|
||||
|
||||
while (true)
|
||||
{
|
||||
DebugStackFrameDescriptor descriptor;
|
||||
uint countFetched;
|
||||
enumFrames.Next(1, out descriptor, out countFetched);
|
||||
if (countFetched < 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string description;
|
||||
descriptor.Frame.GetDescriptionString(true, out description);
|
||||
|
||||
IDebugCodeContext codeContext;
|
||||
descriptor.Frame.GetCodeContext(out codeContext);
|
||||
|
||||
IDebugDocumentContext documentContext;
|
||||
codeContext.GetDocumentContext(out documentContext);
|
||||
if (documentContext == null)
|
||||
{
|
||||
stackTrace += MiscHelpers.FormatInvariant(" at {0}\n", description);
|
||||
}
|
||||
else
|
||||
{
|
||||
IDebugDocument document;
|
||||
documentContext.GetDocument(out document);
|
||||
var documentText = (IDebugDocumentText)document;
|
||||
|
||||
string documentName;
|
||||
document.GetName(DocumentNameType.Title, out documentName);
|
||||
|
||||
uint position;
|
||||
uint length;
|
||||
documentText.GetPositionOfContext(documentContext, out position, out length);
|
||||
|
||||
var pBuffer = Marshal.AllocCoTaskMem((int)(sizeof(char) * length));
|
||||
try
|
||||
{
|
||||
uint lengthReturned = 0;
|
||||
documentText.GetText(position, pBuffer, IntPtr.Zero, ref lengthReturned, length);
|
||||
var codeLine = Marshal.PtrToStringUni(pBuffer, (int)lengthReturned);
|
||||
|
||||
uint lineNumber;
|
||||
uint offsetInLine;
|
||||
documentText.GetLineOfPosition(position, out lineNumber, out offsetInLine);
|
||||
|
||||
stackTrace += MiscHelpers.FormatInvariant(" at {0} ({1}:{2}:{3}) -> {4}\n", description, documentName, lineNumber, offsetInLine, codeLine);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeCoTaskMem(pBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (descriptor.FinalObject != null)
|
||||
{
|
||||
Marshal.ReleaseComObject(descriptor.FinalObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stackTrace.TrimEnd('\n');
|
||||
}
|
||||
|
||||
private void VerifyNotDisposed()
|
||||
{
|
||||
if (disposed)
|
||||
|
@ -256,6 +332,24 @@ namespace Microsoft.ClearScript.Windows
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string representation of the script call stack.
|
||||
/// </summary>
|
||||
/// <returns>The script call stack formatted as a string.</returns>
|
||||
/// <remarks>
|
||||
/// This method returns an empty string if the script engine is not executing script code.
|
||||
/// The stack trace text format is defined by the script engine.
|
||||
/// <para>
|
||||
/// The <see cref="WindowsScriptEngine"/> version of this method returns the empty string
|
||||
/// if script debugging features have not been enabled for the instance.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public override string GetStackTrace()
|
||||
{
|
||||
VerifyNotDisposed();
|
||||
return engineFlags.HasFlag(WindowsScriptEngineFlags.EnableDebugging) ? ScriptInvoke(() => GetStackTraceInternal()) : string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interrupts script execution and causes the script engine to throw an exception.
|
||||
/// </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.3.9.0")]
|
||||
[assembly: AssemblyFileVersion("5.3.9.0")]
|
||||
[assembly: AssemblyVersion("5.3.10.0")]
|
||||
[assembly: AssemblyFileVersion("5.3.10.0")]
|
||||
|
|
|
@ -69,5 +69,5 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCopyright("(c) Microsoft Corporation")]
|
||||
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: AssemblyVersion("5.3.9.0")]
|
||||
[assembly: AssemblyFileVersion("5.3.9.0")]
|
||||
[assembly: AssemblyVersion("5.3.10.0")]
|
||||
[assembly: AssemblyFileVersion("5.3.10.0")]
|
||||
|
|
|
@ -293,8 +293,74 @@ namespace Microsoft.ClearScript.Test
|
|||
Assert.AreEqual(456, engine.Evaluate("expando.property('bar')"));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("BugFix")]
|
||||
public void BugFix_Nullable_Field()
|
||||
{
|
||||
engine.Script.test = new NullableTest();
|
||||
Assert.IsNull(engine.Evaluate("test.Field"));
|
||||
Assert.IsTrue((bool)engine.Evaluate("test.Field === null"));
|
||||
engine.Execute("test.Field = 123");
|
||||
Assert.AreEqual(123, engine.Evaluate("test.Field"));
|
||||
Assert.IsTrue((bool)engine.Evaluate("test.Field === 123"));
|
||||
engine.Execute("test.Field = null");
|
||||
Assert.IsNull(engine.Evaluate("test.Field"));
|
||||
Assert.IsTrue((bool)engine.Evaluate("test.Field === null"));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("BugFix")]
|
||||
public void BugFix_Nullable_Property()
|
||||
{
|
||||
engine.Script.test = new NullableTest();
|
||||
Assert.IsNull(engine.Evaluate("test.Property"));
|
||||
Assert.IsTrue((bool)engine.Evaluate("test.Property === null"));
|
||||
engine.Execute("test.Property = 123");
|
||||
Assert.AreEqual(123, engine.Evaluate("test.Property"));
|
||||
Assert.IsTrue((bool)engine.Evaluate("test.Property === 123"));
|
||||
engine.Execute("test.Property = null");
|
||||
Assert.IsNull(engine.Evaluate("test.Property"));
|
||||
Assert.IsTrue((bool)engine.Evaluate("test.Property === null"));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("BugFix")]
|
||||
public void BugFix_Nullable_ArgBinding()
|
||||
{
|
||||
var test = new NullableTest();
|
||||
engine.Script.test = test;
|
||||
Assert.IsNull(engine.Evaluate("test.Method(null)"));
|
||||
Assert.AreEqual(test.Method(5), engine.Evaluate("test.Method(5)"));
|
||||
Assert.AreEqual(test.Method(5.1), engine.Evaluate("test.Method(5.1)"));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("BugFix")]
|
||||
public void BugFix_GlobalObjectCrash()
|
||||
{
|
||||
engine.AddHostObject("random", HostItemFlags.GlobalMembers, new Random());
|
||||
Assert.AreEqual("[object global]", engine.ExecuteCommand("this"));
|
||||
}
|
||||
|
||||
// ReSharper restore InconsistentNaming
|
||||
|
||||
#endregion
|
||||
|
||||
#region miscellaneous
|
||||
|
||||
public class NullableTest
|
||||
{
|
||||
public int? Field;
|
||||
|
||||
public double? Property;
|
||||
|
||||
public object Method(int? value)
|
||||
{
|
||||
return value.HasValue ? (value + 1) : null;
|
||||
}
|
||||
|
||||
public object Method(double? value)
|
||||
{
|
||||
return value.HasValue ? (value * 2.0) : null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -927,6 +927,43 @@ namespace Microsoft.ClearScript.Test
|
|||
Assert.AreEqual(Math.Sqrt(7), engine.Evaluate("testObject.Item.get(123, '456', 789.987, -0.12345)"));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("JScriptEngine")]
|
||||
public void JScriptEngine_FormatCode()
|
||||
{
|
||||
try
|
||||
{
|
||||
engine.Execute("a", "\n\n\n x = 3.a");
|
||||
}
|
||||
catch (ScriptEngineException exception)
|
||||
{
|
||||
Assert.IsTrue(exception.ErrorDetails.Contains("(a:3:11)"));
|
||||
}
|
||||
|
||||
engine.FormatCode = true;
|
||||
try
|
||||
{
|
||||
engine.Execute("b", "\n\n\n x = 3.a");
|
||||
}
|
||||
catch (ScriptEngineException exception)
|
||||
{
|
||||
Assert.IsTrue(exception.ErrorDetails.Contains("(b:0:6)"));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("JScriptEngine")]
|
||||
public void JScriptEngine_GetStackTrace()
|
||||
{
|
||||
engine.AddHostObject("qux", new Func<object>(() => engine.GetStackTrace()));
|
||||
engine.Execute(@"
|
||||
function baz() { return qux(); }
|
||||
function bar() { return baz(); }
|
||||
function foo() { return bar(); }
|
||||
");
|
||||
|
||||
Assert.AreEqual(" at baz (Script Document:1:33) -> return qux()\n at bar (Script Document:2:33) -> return baz()\n at foo (Script Document:3:33) -> return bar()\n at JScript global code (Script Document [2] [temp]:0:0) -> foo()", engine.Evaluate("foo()"));
|
||||
Assert.AreEqual(" at baz (Script Document:1:33) -> return qux()\n at bar (Script Document:2:33) -> return baz()\n at foo (Script Document:3:33) -> return bar()", engine.Script.foo());
|
||||
}
|
||||
|
||||
// ReSharper restore InconsistentNaming
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -100,7 +100,7 @@ namespace Microsoft.ClearScript.Test
|
|||
return hashCode * Math.E / Math.PI;
|
||||
}
|
||||
|
||||
public static void AssertException<T>(Action action) where T : Exception
|
||||
public static void AssertException<T>(Action action, bool checkScriptStackTrace = true) where T : Exception
|
||||
{
|
||||
var gotException = false;
|
||||
|
||||
|
@ -111,12 +111,12 @@ namespace Microsoft.ClearScript.Test
|
|||
catch (T exception)
|
||||
{
|
||||
gotException = true;
|
||||
AssertValidExceptionChain(exception);
|
||||
AssertValidExceptionChain(exception, checkScriptStackTrace);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
gotException = exception.GetBaseException() is T;
|
||||
AssertValidExceptionChain(exception);
|
||||
AssertValidExceptionChain(exception, checkScriptStackTrace);
|
||||
}
|
||||
|
||||
Assert.IsTrue(gotException, "Expected " + typeof(T).Name + " was not thrown.");
|
||||
|
@ -131,30 +131,33 @@ namespace Microsoft.ClearScript.Test
|
|||
Assert.IsFalse(string.IsNullOrWhiteSpace(exception.StackTrace));
|
||||
}
|
||||
|
||||
public static void AssertValidException(IScriptEngineException exception)
|
||||
public static void AssertValidException(IScriptEngineException exception, bool checkScriptStackTrace = true)
|
||||
{
|
||||
AssertValidException((Exception)exception);
|
||||
if ((exception is ScriptEngineException) && !exception.IsFatal && (exception.HResult != RawCOMHelpers.HResult.CLEARSCRIPT_E_SCRIPTITEMEXCEPTION))
|
||||
{
|
||||
Assert.IsTrue(exception.ErrorDetails.StartsWith(exception.Message, StringComparison.Ordinal));
|
||||
Assert.IsTrue(exception.ErrorDetails.Contains("\n at "));
|
||||
if (checkScriptStackTrace)
|
||||
{
|
||||
Assert.IsTrue(exception.ErrorDetails.Contains("\n at "));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void AssertValidException(ScriptEngine engine, IScriptEngineException exception)
|
||||
public static void AssertValidException(ScriptEngine engine, IScriptEngineException exception, bool checkScriptStackTrace = true)
|
||||
{
|
||||
AssertValidException(exception);
|
||||
AssertValidException(exception, checkScriptStackTrace);
|
||||
Assert.AreEqual(engine.Name, exception.EngineName);
|
||||
}
|
||||
|
||||
private static void AssertValidExceptionChain(Exception exception)
|
||||
private static void AssertValidExceptionChain(Exception exception, bool checkScriptStackTrace)
|
||||
{
|
||||
while (exception != null)
|
||||
{
|
||||
var scriptError = exception as IScriptEngineException;
|
||||
if (scriptError != null)
|
||||
{
|
||||
AssertValidException(scriptError);
|
||||
AssertValidException(scriptError, checkScriptStackTrace);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -69,5 +69,5 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCopyright("(c) Microsoft Corporation")]
|
||||
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: AssemblyVersion("5.3.9.0")]
|
||||
[assembly: AssemblyFileVersion("5.3.9.0")]
|
||||
[assembly: AssemblyVersion("5.3.10.0")]
|
||||
[assembly: AssemblyFileVersion("5.3.10.0")]
|
||||
|
|
|
@ -269,7 +269,10 @@ namespace Microsoft.ClearScript.Test
|
|||
|
||||
Action innerTest = () =>
|
||||
{
|
||||
using (var scriptEngine = new VBScriptEngine(WindowsScriptEngineFlags.EnableDebugging))
|
||||
// The Visual Studio 2013 debugging stack fails to release the engine properly,
|
||||
// resulting in test failure. Visual Studio 2012 does not have this bug.
|
||||
|
||||
using (var scriptEngine = new VBScriptEngine())
|
||||
{
|
||||
scriptEngine.AddHostObject("bag", bag);
|
||||
Assert.AreEqual(2, bag.EngineCount);
|
||||
|
@ -290,7 +293,10 @@ namespace Microsoft.ClearScript.Test
|
|||
var innerBag = new PropertyBag();
|
||||
Action innerTest = () =>
|
||||
{
|
||||
using (var scriptEngine = new VBScriptEngine(WindowsScriptEngineFlags.EnableDebugging))
|
||||
// The Visual Studio 2013 debugging stack fails to release the engine properly,
|
||||
// resulting in test failure. Visual Studio 2012 does not have this bug.
|
||||
|
||||
using (var scriptEngine = new VBScriptEngine())
|
||||
{
|
||||
scriptEngine.AddHostObject("bag", outerBag);
|
||||
outerBag.Add("innerBag", innerBag);
|
||||
|
|
|
@ -1127,6 +1127,108 @@ namespace Microsoft.ClearScript.Test
|
|||
Assert.AreEqual(Math.Sqrt(7), engine.Evaluate("testObject.Item.get(123, '456', 789.987, -0.12345)"));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("V8ScriptEngine")]
|
||||
public void V8ScriptEngine_FormatCode()
|
||||
{
|
||||
try
|
||||
{
|
||||
engine.Execute("a", "\n\n\n x = 3.a");
|
||||
}
|
||||
catch (ScriptEngineException exception)
|
||||
{
|
||||
Assert.IsTrue(exception.ErrorDetails.Contains(" a:4:10 "));
|
||||
}
|
||||
|
||||
engine.FormatCode = true;
|
||||
try
|
||||
{
|
||||
engine.Execute("b", "\n\n\n x = 3.a");
|
||||
}
|
||||
catch (ScriptEngineException exception)
|
||||
{
|
||||
Assert.IsTrue(exception.ErrorDetails.Contains(" b:1:5 "));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("V8ScriptEngine")]
|
||||
public void V8ScriptEngine_GetStackTrace()
|
||||
{
|
||||
engine.AddHostObject("qux", new Func<object>(() => engine.GetStackTrace()));
|
||||
engine.Execute(@"
|
||||
function baz() { return qux(); }
|
||||
function bar() { return baz(); }
|
||||
function foo() { return bar(); }
|
||||
");
|
||||
|
||||
Assert.AreEqual(" at baz (Script Document:2:41)\n at bar (Script Document:3:41)\n at foo (Script Document:4:41)\n at Script Document [2] [temp]:1:1", engine.Evaluate("foo()"));
|
||||
Assert.AreEqual(" at baz (Script Document:2:41)\n at bar (Script Document:3:41)\n at foo (Script Document:4:41)", engine.Script.foo());
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("V8ScriptEngine")]
|
||||
public void V8ScriptEngine_MaxRuntimeStackUsage()
|
||||
{
|
||||
using (var runtime = new V8Runtime())
|
||||
{
|
||||
using (var engine1 = runtime.CreateScriptEngine())
|
||||
{
|
||||
using (var engine2 = runtime.CreateScriptEngine())
|
||||
{
|
||||
var value = (UIntPtr)123456;
|
||||
engine1.MaxRuntimeStackUsage = value;
|
||||
Assert.AreEqual(value, engine1.MaxRuntimeStackUsage);
|
||||
Assert.AreEqual(value, engine2.MaxRuntimeStackUsage);
|
||||
Assert.AreEqual(value, runtime.MaxStackUsage);
|
||||
|
||||
value = (UIntPtr)654321;
|
||||
runtime.MaxStackUsage = value;
|
||||
Assert.AreEqual(value, engine1.MaxRuntimeStackUsage);
|
||||
Assert.AreEqual(value, engine2.MaxRuntimeStackUsage);
|
||||
Assert.AreEqual(value, runtime.MaxStackUsage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("V8ScriptEngine")]
|
||||
public void V8ScriptEngine_MaxRuntimeStackUsage_ScriptOnly()
|
||||
{
|
||||
engine.MaxRuntimeStackUsage = (UIntPtr)(16 * 1024);
|
||||
TestUtil.AssertException<ScriptEngineException>(() => engine.Execute("(function () { arguments.callee(); })()"), false);
|
||||
Assert.AreEqual(Math.PI, engine.Evaluate("Math.PI"));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("V8ScriptEngine")]
|
||||
public void V8ScriptEngine_MaxRuntimeStackUsage_HostBounce()
|
||||
{
|
||||
engine.MaxRuntimeStackUsage = (UIntPtr)(16 * 1024);
|
||||
dynamic foo = engine.Evaluate("(function () { arguments.callee(); })");
|
||||
engine.Script.bar = new Action(() => foo());
|
||||
TestUtil.AssertException<ScriptEngineException>(() => engine.Execute("bar()"), false);
|
||||
Assert.AreEqual(Math.PI, engine.Evaluate("Math.PI"));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("V8ScriptEngine")]
|
||||
public void V8ScriptEngine_MaxRuntimeStackUsage_Alternating()
|
||||
{
|
||||
engine.MaxRuntimeStackUsage = (UIntPtr)(16 * 1024);
|
||||
dynamic foo = engine.Evaluate("(function () { bar(); })");
|
||||
engine.Script.bar = new Action(() => foo());
|
||||
TestUtil.AssertException<ScriptEngineException>(() => foo(), false);
|
||||
Assert.AreEqual(Math.PI, engine.Evaluate("Math.PI"));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("V8ScriptEngine")]
|
||||
public void V8ScriptEngine_MaxRuntimeStackUsage_Expansion()
|
||||
{
|
||||
engine.MaxRuntimeStackUsage = (UIntPtr)(16 * 1024);
|
||||
TestUtil.AssertException<ScriptEngineException>(() => engine.Execute("count = 0; (function () { count++; arguments.callee(); })()"), false);
|
||||
var count1 = engine.Script.count;
|
||||
engine.MaxRuntimeStackUsage = (UIntPtr)(64 * 1024);
|
||||
TestUtil.AssertException<ScriptEngineException>(() => engine.Execute("count = 0; (function () { count++; arguments.callee(); })()"), false);
|
||||
var count2 = engine.Script.count;
|
||||
Assert.IsTrue(count2 >= (count1 * 2));
|
||||
}
|
||||
|
||||
// ReSharper restore InconsistentNaming
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -863,6 +863,43 @@ namespace Microsoft.ClearScript.Test
|
|||
Assert.AreEqual(Math.Sqrt(7), engine.Evaluate("testObject.Item.get(clng(123), \"456\", 789.987, -0.12345)"));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("VBScriptEngine")]
|
||||
public void VBScriptEngine_FormatCode()
|
||||
{
|
||||
try
|
||||
{
|
||||
engine.Execute("a", "\n\n\n x = 3.a");
|
||||
}
|
||||
catch (ScriptEngineException exception)
|
||||
{
|
||||
Assert.IsTrue(exception.ErrorDetails.Contains("(a:3:11)"));
|
||||
}
|
||||
|
||||
engine.FormatCode = true;
|
||||
try
|
||||
{
|
||||
engine.Execute("b", "\n\n\n x = 3.a");
|
||||
}
|
||||
catch (ScriptEngineException exception)
|
||||
{
|
||||
Assert.IsTrue(exception.ErrorDetails.Contains("(b:0:6)"));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("VBScriptEngine")]
|
||||
public void VBScriptEngine_GetStackTrace()
|
||||
{
|
||||
engine.AddHostObject("qux", new Func<object>(() => engine.GetStackTrace()));
|
||||
engine.Execute(@"
|
||||
function baz():baz = qux():end function
|
||||
function bar():bar = baz():end function
|
||||
function foo():foo = bar():end function
|
||||
");
|
||||
|
||||
Assert.AreEqual(" at baz (Script Document [3]:1:31) -> baz = qux()\n at bar (Script Document [3]:2:31) -> bar = baz()\n at foo (Script Document [3]:3:31) -> foo = bar()\n at VBScript global code (Script Document [4] [temp]:0:0) -> foo()", engine.Evaluate("foo()"));
|
||||
Assert.AreEqual(" at baz (Script Document [3]:1:31) -> baz = qux()\n at bar (Script Document [3]:2:31) -> bar = baz()\n at foo (Script Document [3]:3:31) -> foo = bar()", engine.Script.foo());
|
||||
}
|
||||
|
||||
// ReSharper restore InconsistentNaming
|
||||
|
||||
#endregion
|
||||
|
|
20
ReadMe.txt
20
ReadMe.txt
|
@ -20,9 +20,9 @@ See ClearScript\doc for information about using ClearScript.
|
|||
II. Building ClearScript
|
||||
------------------------
|
||||
|
||||
The provided project and solution files require Visual Studio 2012. They
|
||||
produce architecture-neutral managed libraries that target .NET Framework 4.0.
|
||||
ClearScript has been tested with .NET Framework 4.5 as well. It does not
|
||||
The provided project and solution files support Visual Studio 2012 and 2013.
|
||||
They produce architecture-neutral managed libraries that target .NET Framework
|
||||
4.0. ClearScript has been tested with .NET Framework 4.5 as well. It does not
|
||||
support older environments. The output directory is bin\[Debug|Release].
|
||||
|
||||
There are two ways to build ClearScript - with and without V8 support.
|
||||
|
@ -66,6 +66,10 @@ build, and import V8:
|
|||
|
||||
You are now ready to build the full ClearScript solution using Visual Studio.
|
||||
|
||||
NOTE: The first time you open the solution, Visual Studio may prompt you to
|
||||
upgrade one or more projects to the latest platform toolset or .NET Framework.
|
||||
We recommend that you select "Cancel" or "Don't Upgrade".
|
||||
|
||||
OPTIONAL: The ClearScript distribution includes a copy of the ClearScript
|
||||
Library Reference in Compiled HTML (.CHM) format. If you'd like to rebuild this
|
||||
file, use Sandcastle Help File Builder (SHFB, http://shfb.codeplex.com) with
|
||||
|
@ -90,11 +94,19 @@ Once you've built ClearScript, here's how to add it to your application:
|
|||
ClearScriptV8-64.dll
|
||||
v8-ia32.dll
|
||||
v8-x64.dll
|
||||
|
||||
For ASP.NET projects, we recommend that you add these assemblies as content
|
||||
files at the root of your web application and set their "Copy to Output
|
||||
Directory" properties to "Do not copy".
|
||||
|
||||
In addition, if Visual Studio is not installed on the deployment machine,
|
||||
4. IMPORTANT: If Visual Studio is not installed on your deployment machine,
|
||||
you must install 32-bit and 64-bit Visual C++ Redistributable packages:
|
||||
|
||||
Visual Studio 2012:
|
||||
http://www.microsoft.com/en-us/download/details.aspx?id=30679
|
||||
|
||||
Visual Studio 2013:
|
||||
http://www.microsoft.com/en-us/download/details.aspx?id=40784
|
||||
|
||||
-------------------------------------
|
||||
IV. Debugging with ClearScript and V8
|
||||
|
|
11
V8Update.cmd
11
V8Update.cmd
|
@ -5,8 +5,8 @@ setlocal
|
|||
:: process arguments
|
||||
::-----------------------------------------------------------------------------
|
||||
|
||||
set testedRevision=17421
|
||||
set testedVersion=3.22.23
|
||||
set testedRevision=18109
|
||||
set testedVersion=3.23.13
|
||||
|
||||
set gyprev=1685
|
||||
set pythonrev=89111
|
||||
|
@ -162,7 +162,14 @@ cd ..
|
|||
|
||||
:Build
|
||||
|
||||
:SetMSVSVersion
|
||||
if "%VisualStudioVersion%"=="12.0" goto UseMSVS2013
|
||||
set GYP_MSVS_VERSION=2012
|
||||
goto SetMSVSVersionDone
|
||||
:UseMSVS2013
|
||||
set GYP_MSVS_VERSION=2013
|
||||
:SetMSVSVersionDone
|
||||
|
||||
set PYTHONHOME=
|
||||
set PYTHONPATH=
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
<# var version = new Version(5, 3, 9, 0); #>
|
||||
<# var version = new Version(5, 3, 10, 0); #>
|
||||
|
|
Загрузка…
Ссылка в новой задаче