Version 5.4.4: Added fast data transfer between host arrays and JavaScript typed arrays (and other ArrayBuffer views) (Issue #83); IEnumerable instances now support ES6 iteration and for...of when exposed in V8ScriptEngine; added fully dynamic treatment for exposed IDispatchEx instances (Issue #96); fixed host member enumeration and deletion on JScript with Standards Mode (Issue #94); improved numeric argument conversion and matching (Issue #95); fixed nested termination behavior on V8; added tests for bug fixes and new APIs. Tested with V8 4.7.80.25.
This commit is contained in:
Родитель
ba8bf459e4
Коммит
4d6048f4be
|
@ -27,6 +27,7 @@ obj/
|
|||
_ReSharper*/
|
||||
[Tt]est[Rr]esult*
|
||||
*.sdf
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.shfbproj_*
|
||||
ClearScript/V8/V8/build/
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp40</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Ecpp/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Eh/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeRedundantParentheses/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertIfStatementToConditionalTernaryExpression/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertIfStatementToNullCoalescingExpression/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ImpureMethodCallOnReadonlyValueField/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp40</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Ecpp/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Eh/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeRedundantParentheses/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertIfStatementToConditionalTernaryExpression/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertIfStatementToNullCoalescingExpression/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ImpureMethodCallOnReadonlyValueField/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||
|
|
|
@ -69,6 +69,10 @@
|
|||
<Compile Include="BindSignature.cs" />
|
||||
<Compile Include="IScriptEngineException.cs" />
|
||||
<Compile Include="DefaultScriptUsageAttribute.cs" />
|
||||
<Compile Include="JavaScript\IArrayBuffer.cs" />
|
||||
<Compile Include="JavaScript\IArrayBufferView.cs" />
|
||||
<Compile Include="JavaScript\IDataView.cs" />
|
||||
<Compile Include="JavaScript\ITypedArray.cs" />
|
||||
<Compile Include="NoDefaultScriptAccessAttribute.cs" />
|
||||
<Compile Include="NoScriptAccessAttribute.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs">
|
||||
|
@ -97,7 +101,11 @@
|
|||
<Compile Include="Util\Scope.cs" />
|
||||
<Compile Include="Util\SocketHelpers.cs" />
|
||||
<Compile Include="Util\SpecialDispIDs.cs" />
|
||||
<Compile Include="Util\UnmanagedMemoryHelpers.cs" />
|
||||
<Compile Include="Util\VTablePatcher.cs" />
|
||||
<Compile Include="V8\IV8DebugListener.cs" />
|
||||
<Compile Include="V8\V8ArrayBufferOrViewInfo.cs" />
|
||||
<Compile Include="V8\V8ArrayBufferOrViewKind.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.3.0"
|
||||
#define CLEARSCRIPT_VERSION_COMMA_SEPARATED 5,4,3,0
|
||||
#define CLEARSCRIPT_VERSION_STRING "5.4.4.0"
|
||||
#define CLEARSCRIPT_VERSION_COMMA_SEPARATED 5,4,4,0
|
||||
|
|
|
@ -343,7 +343,11 @@ namespace Microsoft.ClearScript
|
|||
if (arg != null)
|
||||
{
|
||||
flags |= CSharpArgumentInfoFlags.UseCompileTimeType;
|
||||
if (arg is IOutArg)
|
||||
if (arg is int)
|
||||
{
|
||||
flags |= CSharpArgumentInfoFlags.Constant;
|
||||
}
|
||||
else if (arg is IOutArg)
|
||||
{
|
||||
flags |= CSharpArgumentInfoFlags.IsOut;
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ using Microsoft.ClearScript.Util;
|
|||
|
||||
namespace Microsoft.ClearScript
|
||||
{
|
||||
internal partial class HostItem : DynamicObject, IExpando, IDynamic, IEnumVARIANT, ICustomQueryInterface, IScriptMarshalWrapper, IHostInvokeContext
|
||||
internal partial class HostItem : DynamicObject, IReflect, IDynamic, IEnumVARIANT, ICustomQueryInterface, IScriptMarshalWrapper, IHostInvokeContext
|
||||
{
|
||||
#region data
|
||||
|
||||
|
@ -87,6 +87,9 @@ namespace Microsoft.ClearScript
|
|||
private ScriptAccess defaultAccess;
|
||||
private HostTargetMemberData targetMemberData;
|
||||
|
||||
internal static bool EnableVTablePatching;
|
||||
[ThreadStatic] private static bool bypassVTablePatching;
|
||||
|
||||
#endregion
|
||||
|
||||
#region constructors
|
||||
|
@ -97,11 +100,7 @@ namespace Microsoft.ClearScript
|
|||
this.target = target;
|
||||
this.flags = flags;
|
||||
|
||||
if ((target is HostObject) || (target is IHostVariable) || (target is IByRefArg))
|
||||
{
|
||||
BindSpecialTarget();
|
||||
}
|
||||
|
||||
BindSpecialTarget();
|
||||
BindTargetMemberData();
|
||||
|
||||
var scriptableObject = target.Target as IScriptableObject;
|
||||
|
@ -262,7 +261,7 @@ namespace Microsoft.ClearScript
|
|||
|
||||
#region interface accessors
|
||||
|
||||
private IExpando ThisExpando
|
||||
private IReflect ThisReflect
|
||||
{
|
||||
get { return this; }
|
||||
}
|
||||
|
@ -431,34 +430,37 @@ namespace Microsoft.ClearScript
|
|||
|
||||
private static HostItem Create(ScriptEngine engine, HostTarget target, HostItemFlags flags)
|
||||
{
|
||||
return new HostItem(engine, target, flags);
|
||||
return TargetSupportsExpandoMembers(target, flags) ? new ExpandoHostItem(engine, target, flags) : new HostItem(engine, target, flags);
|
||||
}
|
||||
|
||||
private void BindSpecialTarget()
|
||||
{
|
||||
if (BindSpecialTarget(Collateral.TargetDynamic))
|
||||
if (TargetSupportsSpecialTargets(target))
|
||||
{
|
||||
TargetPropertyBag = null;
|
||||
TargetList = null;
|
||||
TargetDynamicMetaObject = null;
|
||||
}
|
||||
else if (BindSpecialTarget(Collateral.TargetPropertyBag))
|
||||
{
|
||||
TargetList = null;
|
||||
TargetDynamicMetaObject = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
IDynamicMetaObjectProvider dynamicMetaObjectProvider;
|
||||
if (!flags.HasFlag(HostItemFlags.HideDynamicMembers) && BindSpecialTarget(out dynamicMetaObjectProvider))
|
||||
if (BindSpecialTarget(Collateral.TargetDynamic))
|
||||
{
|
||||
TargetDynamicMetaObject = dynamicMetaObjectProvider.GetMetaObject(Expression.Constant(target.InvokeTarget));
|
||||
TargetPropertyBag = null;
|
||||
TargetList = null;
|
||||
TargetDynamicMetaObject = null;
|
||||
}
|
||||
else if (BindSpecialTarget(Collateral.TargetPropertyBag))
|
||||
{
|
||||
TargetList = null;
|
||||
TargetDynamicMetaObject = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
TargetDynamicMetaObject = null;
|
||||
BindSpecialTarget(Collateral.TargetList);
|
||||
IDynamicMetaObjectProvider dynamicMetaObjectProvider;
|
||||
if (!flags.HasFlag(HostItemFlags.HideDynamicMembers) && BindSpecialTarget(out dynamicMetaObjectProvider))
|
||||
{
|
||||
TargetDynamicMetaObject = dynamicMetaObjectProvider.GetMetaObject(Expression.Constant(target.InvokeTarget));
|
||||
TargetList = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
TargetDynamicMetaObject = null;
|
||||
BindSpecialTarget(Collateral.TargetList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -478,6 +480,18 @@ namespace Microsoft.ClearScript
|
|||
|
||||
private bool BindSpecialTarget<T>(out T specialTarget) where T : class
|
||||
{
|
||||
// provide fully dynamic behavior for exposed IDispatchEx implementations
|
||||
|
||||
if (typeof(T) == typeof(IDynamic))
|
||||
{
|
||||
var dispatchEx = target.InvokeTarget as IDispatchEx;
|
||||
if ((dispatchEx != null) && dispatchEx.GetType().IsCOMObject)
|
||||
{
|
||||
specialTarget = (T)(object)(new DynamicDispatchExWrapper(dispatchEx));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// The check here is required because the item may be bound to a specific target base
|
||||
// class or interface - one that must not trigger special treatment.
|
||||
|
||||
|
@ -531,6 +545,57 @@ namespace Microsoft.ClearScript
|
|||
}
|
||||
}
|
||||
|
||||
private static bool TargetSupportsSpecialTargets(HostTarget target)
|
||||
{
|
||||
return (target is HostObject) || (target is IHostVariable) || (target is IByRefArg);
|
||||
}
|
||||
|
||||
private static bool TargetSupportsExpandoMembers(HostTarget target, HostItemFlags flags)
|
||||
{
|
||||
if (!TargetSupportsSpecialTargets(target))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof(IDynamic).IsAssignableFrom(target.Type))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (target is IHostVariable)
|
||||
{
|
||||
if (target.Type.IsImport)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var dispatchEx = target.InvokeTarget as IDispatchEx;
|
||||
if ((dispatchEx != null) && dispatchEx.GetType().IsCOMObject)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof(IPropertyBag).IsAssignableFrom(target.Type))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!flags.HasFlag(HostItemFlags.HideDynamicMembers) && typeof(IDynamicMetaObjectProvider).IsAssignableFrom(target.Type))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool CanAddExpandoMembers()
|
||||
{
|
||||
return (TargetDynamic != null) || ((TargetPropertyBag != null) && !TargetPropertyBag.IsReadOnly) || (TargetDynamicMetaObject != null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region member data maintenance
|
||||
|
@ -892,7 +957,7 @@ namespace Microsoft.ClearScript
|
|||
{
|
||||
if (invokeFlags.HasFlag(BindingFlags.GetField) && (args.Length < 1))
|
||||
{
|
||||
return TargetDynamic.GetProperty(name);
|
||||
return TargetDynamic.GetProperty(name, args);
|
||||
}
|
||||
|
||||
throw;
|
||||
|
@ -901,16 +966,15 @@ namespace Microsoft.ClearScript
|
|||
|
||||
if (invokeFlags.HasFlag(BindingFlags.GetField))
|
||||
{
|
||||
return TargetDynamic.GetProperty(name);
|
||||
return TargetDynamic.GetProperty(name, args);
|
||||
}
|
||||
|
||||
if (invokeFlags.HasFlag(BindingFlags.SetField))
|
||||
{
|
||||
if (args.Length == 1)
|
||||
if (args.Length > 0)
|
||||
{
|
||||
var value = args[0];
|
||||
TargetDynamic.SetProperty(name, value);
|
||||
return value;
|
||||
TargetDynamic.SetProperty(name, args);
|
||||
return args[args.Length - 1];
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Invalid argument count");
|
||||
|
@ -933,6 +997,11 @@ namespace Microsoft.ClearScript
|
|||
throw new NotSupportedException("Object does not support invocation");
|
||||
}
|
||||
|
||||
if (name == SpecialMemberNames.NewEnum)
|
||||
{
|
||||
return HostObject.Wrap(TargetPropertyBag.GetEnumerator(), typeof(IEnumerator));
|
||||
}
|
||||
|
||||
object value;
|
||||
if (!TargetPropertyBag.TryGetValue(name, out value))
|
||||
{
|
||||
|
@ -1121,11 +1190,18 @@ namespace Microsoft.ClearScript
|
|||
IEnumerable enumerable;
|
||||
if (BindSpecialTarget(out enumerable))
|
||||
{
|
||||
return HostObject.Wrap(enumerable.GetEnumerator(), typeof(IEnumerator));
|
||||
var enumerationHelpersHostItem = Wrap(engine, EnumerationHelpers.HostType, HostItemFlags.PrivateAccess);
|
||||
try
|
||||
{
|
||||
return ((IDynamic)enumerationHelpersHostItem).InvokeMethod("GetEnumerator", new object[] { this });
|
||||
}
|
||||
catch (MissingMemberException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotSupportedException("Object is not a collection");
|
||||
throw new NotSupportedException("Object is not enumerable");
|
||||
}
|
||||
|
||||
if ((TargetDynamicMetaObject != null) && (TargetDynamicMetaObject.GetDynamicMemberNames().Contains(name)))
|
||||
|
@ -1136,7 +1212,7 @@ namespace Microsoft.ClearScript
|
|||
}
|
||||
}
|
||||
|
||||
if (ThisExpando.GetMethods(GetMethodBindFlags()).Any(method => method.Name == name))
|
||||
if (ThisReflect.GetMethods(GetMethodBindFlags()).Any(method => method.Name == name))
|
||||
{
|
||||
// The target appears to have a method with the right name, but it could be an
|
||||
// extension method that fails to bind. If that happens, we should attempt the
|
||||
|
@ -1286,7 +1362,7 @@ namespace Microsoft.ClearScript
|
|||
return hostIndexedProperty;
|
||||
}
|
||||
|
||||
var method = ThisExpando.GetMethods(GetMethodBindFlags()).FirstOrDefault(testMethod => testMethod.Name == name);
|
||||
var method = ThisReflect.GetMethods(GetMethodBindFlags()).FirstOrDefault(testMethod => testMethod.Name == name);
|
||||
if (method != null)
|
||||
{
|
||||
if (HostMethodMap == null)
|
||||
|
@ -1443,13 +1519,13 @@ namespace Microsoft.ClearScript
|
|||
|
||||
public override bool TryGetMember(GetMemberBinder binder, out object result)
|
||||
{
|
||||
result = ThisDynamic.GetProperty(binder.Name).ToDynamicResult(engine);
|
||||
result = ThisDynamic.GetProperty(binder.Name, MiscHelpers.GetEmptyArray<object>()).ToDynamicResult(engine);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool TrySetMember(SetMemberBinder binder, object value)
|
||||
{
|
||||
ThisDynamic.SetProperty(binder.Name, value);
|
||||
ThisDynamic.SetProperty(binder.Name, new[] { value });
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1461,12 +1537,16 @@ namespace Microsoft.ClearScript
|
|||
if (MiscHelpers.TryGetIndex(indices[0], out index))
|
||||
{
|
||||
result = ThisDynamic.GetProperty(index).ToDynamicResult(engine);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = ThisDynamic.GetProperty(indices[0].ToString()).ToDynamicResult(engine);
|
||||
return true;
|
||||
}
|
||||
|
||||
result = ThisDynamic.GetProperty(indices[0].ToString(), MiscHelpers.GetEmptyArray<object>()).ToDynamicResult(engine);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (indices.Length > 1)
|
||||
{
|
||||
result = ThisDynamic.GetProperty(SpecialMemberNames.Default, indices);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1481,15 +1561,18 @@ namespace Microsoft.ClearScript
|
|||
if (MiscHelpers.TryGetIndex(indices[0], out index))
|
||||
{
|
||||
ThisDynamic.SetProperty(index, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
ThisDynamic.SetProperty(indices[0].ToString(), value);
|
||||
return true;
|
||||
}
|
||||
|
||||
ThisDynamic.SetProperty(indices[0].ToString(), new[] { value });
|
||||
return true;
|
||||
}
|
||||
|
||||
if (indices.Length > 1)
|
||||
{
|
||||
ThisDynamic.SetProperty(SpecialMemberNames.Default, indices.Concat(new[] { value }).ToArray());
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Invalid argument or index count");
|
||||
}
|
||||
|
||||
|
@ -1526,7 +1609,7 @@ namespace Microsoft.ClearScript
|
|||
|
||||
FieldInfo IReflect.GetField(string name, BindingFlags bindFlags)
|
||||
{
|
||||
var fields = ThisExpando.GetFields(bindFlags).Where(field => field.Name == name).ToArray();
|
||||
var fields = ThisReflect.GetFields(bindFlags).Where(field => field.Name == name).ToArray();
|
||||
if (fields.Length < 1)
|
||||
{
|
||||
return null;
|
||||
|
@ -1561,17 +1644,17 @@ namespace Microsoft.ClearScript
|
|||
|
||||
MemberInfo[] IReflect.GetMember(string name, BindingFlags bindFlags)
|
||||
{
|
||||
return ThisExpando.GetMembers(bindFlags).Where(member => member.Name == name).ToArray();
|
||||
return ThisReflect.GetMembers(bindFlags).Where(member => member.Name == name).ToArray();
|
||||
}
|
||||
|
||||
MemberInfo[] IReflect.GetMembers(BindingFlags bindFlags)
|
||||
{
|
||||
return ThisExpando.GetFields(bindFlags).Cast<MemberInfo>().Concat(ThisExpando.GetMethods(bindFlags)).Concat(ThisExpando.GetProperties(bindFlags)).ToArray();
|
||||
return ThisReflect.GetFields(bindFlags).Cast<MemberInfo>().Concat(ThisReflect.GetMethods(bindFlags)).Concat(ThisReflect.GetProperties(bindFlags)).ToArray();
|
||||
}
|
||||
|
||||
MethodInfo IReflect.GetMethod(string name, BindingFlags bindFlags)
|
||||
{
|
||||
var methods = ThisExpando.GetMethods(bindFlags).Where(method => method.Name == name).ToArray();
|
||||
var methods = ThisReflect.GetMethods(bindFlags).Where(method => method.Name == name).ToArray();
|
||||
if (methods.Length < 1)
|
||||
{
|
||||
return null;
|
||||
|
@ -1635,7 +1718,7 @@ namespace Microsoft.ClearScript
|
|||
|
||||
PropertyInfo IReflect.GetProperty(string name, BindingFlags bindFlags)
|
||||
{
|
||||
var properties = ThisExpando.GetProperties(bindFlags).Where(property => property.Name == name).ToArray();
|
||||
var properties = ThisReflect.GetProperties(bindFlags).Where(property => property.Name == name).ToArray();
|
||||
if (properties.Length < 1)
|
||||
{
|
||||
return null;
|
||||
|
@ -1661,99 +1744,21 @@ namespace Microsoft.ClearScript
|
|||
|
||||
#endregion
|
||||
|
||||
#region IExpando implementation
|
||||
|
||||
FieldInfo IExpando.AddField(string name)
|
||||
{
|
||||
return HostInvoke(() =>
|
||||
{
|
||||
if ((TargetDynamic != null) || ((TargetPropertyBag != null) && !TargetPropertyBag.IsReadOnly) || (TargetDynamicMetaObject != null))
|
||||
{
|
||||
AddExpandoMemberName(name);
|
||||
return MemberMap.GetField(name);
|
||||
}
|
||||
|
||||
throw new NotSupportedException("Object does not support dynamic fields");
|
||||
});
|
||||
}
|
||||
|
||||
PropertyInfo IExpando.AddProperty(string name)
|
||||
{
|
||||
return HostInvoke(() =>
|
||||
{
|
||||
if ((TargetDynamic != null) || ((TargetPropertyBag != null) && !TargetPropertyBag.IsReadOnly) || (TargetDynamicMetaObject != null))
|
||||
{
|
||||
AddExpandoMemberName(name);
|
||||
return MemberMap.GetProperty(name);
|
||||
}
|
||||
|
||||
throw new NotSupportedException("Object does not support dynamic properties");
|
||||
});
|
||||
}
|
||||
|
||||
MethodInfo IExpando.AddMethod(string name, Delegate method)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void IExpando.RemoveMember(MemberInfo member)
|
||||
{
|
||||
HostInvoke(() =>
|
||||
{
|
||||
if (TargetDynamic != null)
|
||||
{
|
||||
int index;
|
||||
if (int.TryParse(member.Name, NumberStyles.Integer, CultureInfo.InvariantCulture, out index))
|
||||
{
|
||||
if (TargetDynamic.DeleteProperty(index))
|
||||
{
|
||||
RemoveExpandoMemberName(index.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
else if (TargetDynamic.DeleteProperty(member.Name))
|
||||
{
|
||||
RemoveExpandoMemberName(member.Name);
|
||||
}
|
||||
}
|
||||
else if (TargetPropertyBag != null)
|
||||
{
|
||||
if (TargetPropertyBag.Remove(member.Name))
|
||||
{
|
||||
RemoveExpandoMemberName(member.Name);
|
||||
}
|
||||
}
|
||||
else if (TargetDynamicMetaObject != null)
|
||||
{
|
||||
bool result;
|
||||
if (TargetDynamicMetaObject.TryDeleteMember(member.Name, out result) && result)
|
||||
{
|
||||
RemoveExpandoMemberName(member.Name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException("Object does not support dynamic members");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDynamic implementation
|
||||
|
||||
object IDynamic.GetProperty(string name)
|
||||
object IDynamic.GetProperty(string name, object[] args)
|
||||
{
|
||||
return InvokeReflectMember(name, BindingFlags.GetProperty, MiscHelpers.GetEmptyArray<object>(), CultureInfo.InvariantCulture, null);
|
||||
return InvokeReflectMember(name, BindingFlags.GetProperty, args, CultureInfo.InvariantCulture, null);
|
||||
}
|
||||
|
||||
object IDynamic.GetProperty(string name, out bool isCacheable)
|
||||
object IDynamic.GetProperty(string name, object[] args, out bool isCacheable)
|
||||
{
|
||||
return InvokeReflectMember(name, BindingFlags.GetProperty, MiscHelpers.GetEmptyArray<object>(), CultureInfo.InvariantCulture, null, out isCacheable);
|
||||
return InvokeReflectMember(name, BindingFlags.GetProperty, args, CultureInfo.InvariantCulture, null, out isCacheable);
|
||||
}
|
||||
|
||||
void IDynamic.SetProperty(string name, object value)
|
||||
void IDynamic.SetProperty(string name, object[] args)
|
||||
{
|
||||
ThisExpando.InvokeMember(name, BindingFlags.SetProperty, null, ThisExpando, new[] { value }, null, CultureInfo.InvariantCulture, null);
|
||||
ThisReflect.InvokeMember(name, BindingFlags.SetProperty, null, ThisReflect, args, null, CultureInfo.InvariantCulture, null);
|
||||
}
|
||||
|
||||
bool IDynamic.DeleteProperty(string name)
|
||||
|
@ -1809,12 +1814,12 @@ namespace Microsoft.ClearScript
|
|||
|
||||
object IDynamic.GetProperty(int index)
|
||||
{
|
||||
return ThisDynamic.GetProperty(index.ToString(CultureInfo.InvariantCulture));
|
||||
return ThisDynamic.GetProperty(index.ToString(CultureInfo.InvariantCulture), MiscHelpers.GetEmptyArray<object>());
|
||||
}
|
||||
|
||||
void IDynamic.SetProperty(int index, object value)
|
||||
{
|
||||
ThisDynamic.SetProperty(index.ToString(CultureInfo.InvariantCulture), value);
|
||||
ThisDynamic.SetProperty(index.ToString(CultureInfo.InvariantCulture), new[] { value });
|
||||
}
|
||||
|
||||
bool IDynamic.DeleteProperty(int index)
|
||||
|
@ -1863,12 +1868,12 @@ namespace Microsoft.ClearScript
|
|||
|
||||
object IDynamic.Invoke(object[] args, bool asConstructor)
|
||||
{
|
||||
return ThisExpando.InvokeMember(SpecialMemberNames.Default, asConstructor ? BindingFlags.CreateInstance : ((args.Length < 1) ? BindingFlags.InvokeMethod : BindingFlags.InvokeMethod | BindingFlags.GetProperty), null, ThisExpando, args, null, CultureInfo.InvariantCulture, null);
|
||||
return ThisReflect.InvokeMember(SpecialMemberNames.Default, asConstructor ? BindingFlags.CreateInstance : ((args.Length < 1) ? BindingFlags.InvokeMethod : BindingFlags.InvokeMethod | BindingFlags.GetProperty), null, ThisReflect, args, null, CultureInfo.InvariantCulture, null);
|
||||
}
|
||||
|
||||
object IDynamic.InvokeMethod(string name, object[] args)
|
||||
{
|
||||
return ThisExpando.InvokeMember(name, BindingFlags.InvokeMethod, null, ThisExpando, args, null, CultureInfo.InvariantCulture, null);
|
||||
return ThisReflect.InvokeMember(name, BindingFlags.InvokeMethod, null, ThisReflect, args, null, CultureInfo.InvariantCulture, null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -1885,7 +1890,7 @@ namespace Microsoft.ClearScript
|
|||
var maxCount = Math.Min(count, elements.Length);
|
||||
while ((index < maxCount) && TargetEnumerator.MoveNext())
|
||||
{
|
||||
elements[index++] = engine.MarshalToScript(TargetEnumerator.Current);
|
||||
elements[index++] = ThisDynamic.GetProperty("Current", MiscHelpers.GetEmptyArray<object>());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1932,15 +1937,35 @@ namespace Microsoft.ClearScript
|
|||
|
||||
public CustomQueryInterfaceResult GetInterface(ref Guid iid, out IntPtr pInterface)
|
||||
{
|
||||
pInterface = IntPtr.Zero;
|
||||
if (iid == typeof(IEnumVARIANT).GUID)
|
||||
{
|
||||
if ((target is HostObject) || (target is IHostVariable) || (target is IByRefArg))
|
||||
{
|
||||
pInterface = IntPtr.Zero;
|
||||
return BindSpecialTarget(Collateral.TargetEnumerator) ? CustomQueryInterfaceResult.NotHandled : CustomQueryInterfaceResult.Failed;
|
||||
}
|
||||
}
|
||||
else if (iid == typeof(IDispatchEx).GUID)
|
||||
{
|
||||
if (EnableVTablePatching && !bypassVTablePatching)
|
||||
{
|
||||
var pUnknown = Marshal.GetIUnknownForObject(this);
|
||||
|
||||
bypassVTablePatching = true;
|
||||
pInterface = RawCOMHelpers.QueryInterfaceNoThrow<IDispatchEx>(pUnknown);
|
||||
bypassVTablePatching = false;
|
||||
|
||||
Marshal.Release(pUnknown);
|
||||
|
||||
if (pInterface != IntPtr.Zero)
|
||||
{
|
||||
VTablePatcher.GetInstance().PatchDispatchEx(pInterface);
|
||||
return CustomQueryInterfaceResult.Handled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pInterface = IntPtr.Zero;
|
||||
return CustomQueryInterfaceResult.NotHandled;
|
||||
}
|
||||
|
||||
|
@ -1968,5 +1993,122 @@ namespace Microsoft.ClearScript
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: ExpandoHostItem
|
||||
|
||||
private class ExpandoHostItem : HostItem, IExpando
|
||||
{
|
||||
#region constructors
|
||||
|
||||
public ExpandoHostItem(ScriptEngine engine, HostTarget target, HostItemFlags flags)
|
||||
: base(engine, target, flags)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IExpando implementation
|
||||
|
||||
FieldInfo IExpando.AddField(string name)
|
||||
{
|
||||
return HostInvoke(() =>
|
||||
{
|
||||
if (CanAddExpandoMembers())
|
||||
{
|
||||
AddExpandoMemberName(name);
|
||||
return MemberMap.GetField(name);
|
||||
}
|
||||
|
||||
throw new NotSupportedException("Object does not support dynamic fields");
|
||||
});
|
||||
}
|
||||
|
||||
PropertyInfo IExpando.AddProperty(string name)
|
||||
{
|
||||
return HostInvoke(() =>
|
||||
{
|
||||
if (CanAddExpandoMembers())
|
||||
{
|
||||
AddExpandoMemberName(name);
|
||||
return MemberMap.GetProperty(name);
|
||||
}
|
||||
|
||||
throw new NotSupportedException("Object does not support dynamic properties");
|
||||
});
|
||||
}
|
||||
|
||||
MethodInfo IExpando.AddMethod(string name, Delegate method)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void IExpando.RemoveMember(MemberInfo member)
|
||||
{
|
||||
HostInvoke(() =>
|
||||
{
|
||||
if (TargetDynamic != null)
|
||||
{
|
||||
int index;
|
||||
if (int.TryParse(member.Name, NumberStyles.Integer, CultureInfo.InvariantCulture, out index))
|
||||
{
|
||||
if (TargetDynamic.DeleteProperty(index))
|
||||
{
|
||||
RemoveExpandoMemberName(index.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
else if (TargetDynamic.DeleteProperty(member.Name))
|
||||
{
|
||||
RemoveExpandoMemberName(member.Name);
|
||||
}
|
||||
}
|
||||
else if (TargetPropertyBag != null)
|
||||
{
|
||||
if (TargetPropertyBag.Remove(member.Name))
|
||||
{
|
||||
RemoveExpandoMemberName(member.Name);
|
||||
}
|
||||
}
|
||||
else if (TargetDynamicMetaObject != null)
|
||||
{
|
||||
bool result;
|
||||
if (TargetDynamicMetaObject.TryDeleteMember(member.Name, out result) && result)
|
||||
{
|
||||
RemoveExpandoMemberName(member.Name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException("Object does not support dynamic members");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: EnumerationHelpers
|
||||
|
||||
private static class EnumerationHelpers
|
||||
{
|
||||
// ReSharper disable UnusedMember.Local
|
||||
|
||||
public static readonly HostType HostType = HostType.Wrap(typeof(EnumerationHelpers));
|
||||
|
||||
public static IEnumerator<T> GetEnumerator<T>(IEnumerable<T> source)
|
||||
{
|
||||
return source.GetEnumerator();
|
||||
}
|
||||
|
||||
public static IEnumerator GetEnumerator(IEnumerable source)
|
||||
{
|
||||
return source.GetEnumerator();
|
||||
}
|
||||
|
||||
// ReSharper restore UnusedMember.Local
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ namespace Microsoft.ClearScript
|
|||
|
||||
#endregion
|
||||
|
||||
#region Nested type : CollateralObject<T>
|
||||
#region Nested type: CollateralObject<T>
|
||||
|
||||
public class CollateralObject<T> : CollateralObject<HostItem, T> where T : class
|
||||
{
|
||||
|
@ -100,7 +100,7 @@ namespace Microsoft.ClearScript
|
|||
|
||||
#endregion
|
||||
|
||||
#region Nested type : ListDataFields
|
||||
#region Nested type: ListDataFields
|
||||
|
||||
public class ListDataFields
|
||||
{
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
//
|
||||
// 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.JavaScript
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a JavaScript
|
||||
/// <see href="https://msdn.microsoft.com/en-us/library/br212474(v=vs.94).aspx">ArrayBuffer</see>.
|
||||
/// </summary>
|
||||
public interface IArrayBuffer
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the size of the <c>ArrayBuffer</c> in bytes.
|
||||
/// </summary>
|
||||
ulong Size { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a byte array containing a copy of the <c>ArrayBuffer</c>'s contents.
|
||||
/// </summary>
|
||||
/// <returns>A new byte array containing a copy of the <c>ArrayBuffer</c>'s contents.</returns>
|
||||
byte[] GetBytes();
|
||||
|
||||
/// <summary>
|
||||
/// Copies bytes from the <c>ArrayBuffer</c> into the specified byte array.
|
||||
/// </summary>
|
||||
/// <param name="offset">The offset within the <c>ArrayBuffer</c> of the first byte to copy.</param>
|
||||
/// <param name="count">The maximum number of bytes to copy.</param>
|
||||
/// <param name="destination">The byte array into which to copy the bytes.</param>
|
||||
/// <param name="destinationIndex">The index within <paramref name="destination"/> at which to store the first copied byte.</param>
|
||||
/// <returns>The number of bytes copied.</returns>
|
||||
ulong ReadBytes(ulong offset, ulong count, byte[] destination, ulong destinationIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Copies bytes from the specified byte array into the <c>ArrayBuffer</c>.
|
||||
/// </summary>
|
||||
/// <param name="source">The byte array from which to copy the bytes.</param>
|
||||
/// <param name="sourceIndex">The index within <paramref name="source"/> of the first byte to copy.</param>
|
||||
/// <param name="count">The maximum number of bytes to copy.</param>
|
||||
/// <param name="offset">The offset within the <c>ArrayBuffer</c> at which to store the first copied byte.</param>
|
||||
/// <returns>The number of bytes copied.</returns>
|
||||
ulong WriteBytes(byte[] source, ulong sourceIndex, ulong count, ulong offset);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
//
|
||||
// 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.JavaScript
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines properties and methods common to all
|
||||
/// <see href="https://msdn.microsoft.com/en-us/library/br212474(v=vs.94).aspx">ArrayBuffer</see>
|
||||
/// views.
|
||||
/// </summary>
|
||||
public interface IArrayBufferView
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets view's underlying <c>ArrayBuffer</c>.
|
||||
/// </summary>
|
||||
IArrayBuffer ArrayBuffer { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the view's offset within the underlying <c>ArrayBuffer</c>.
|
||||
/// </summary>
|
||||
ulong Offset { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the view's size in bytes.
|
||||
/// </summary>
|
||||
ulong Size { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a byte array containing a copy of the view's contents.
|
||||
/// </summary>
|
||||
/// <returns>A new byte array containing a copy of the view's contents.</returns>
|
||||
byte[] GetBytes();
|
||||
|
||||
/// <summary>
|
||||
/// Copies bytes from the view into the specified byte array.
|
||||
/// </summary>
|
||||
/// <param name="offset">The offset within the view of the first byte to copy.</param>
|
||||
/// <param name="count">The maximum number of bytes to copy.</param>
|
||||
/// <param name="destination">The byte array into which to copy the bytes.</param>
|
||||
/// <param name="destinationIndex">The index within <paramref name="destination"/> at which to store the first copied byte.</param>
|
||||
/// <returns>The number of bytes copied.</returns>
|
||||
ulong ReadBytes(ulong offset, ulong count, byte[] destination, ulong destinationIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Copies bytes from the specified byte array into the view.
|
||||
/// </summary>
|
||||
/// <param name="source">The byte array from which to copy the bytes.</param>
|
||||
/// <param name="sourceIndex">The index within <paramref name="source"/> of the first byte to copy.</param>
|
||||
/// <param name="count">The maximum number of bytes to copy.</param>
|
||||
/// <param name="offset">The offset within the view at which to store the first copied byte.</param>
|
||||
/// <returns>The number of bytes copied.</returns>
|
||||
ulong WriteBytes(byte[] source, ulong sourceIndex, ulong count, ulong offset);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
//
|
||||
// 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.JavaScript
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a JavaScript
|
||||
/// <see href="https://msdn.microsoft.com/en-us/library/br212463(v=vs.94).aspx">DataView</see>.
|
||||
/// </summary>
|
||||
public interface IDataView : IArrayBufferView
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
//
|
||||
// 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.JavaScript
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines properties and methods common to all JavaScript
|
||||
/// <see href="https://msdn.microsoft.com/en-us/library/br212485(v=vs.94).aspx">typed arrays</see>.
|
||||
/// </summary>
|
||||
public interface ITypedArray : IArrayBufferView
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the typed array's length.
|
||||
/// </summary>
|
||||
ulong Length { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a JavaScript <see href="https://msdn.microsoft.com/en-us/library/br212485(v=vs.94).aspx">typed array</see>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The typed array's element type.</typeparam>
|
||||
/// <remarks>
|
||||
/// The following table lists the specific interfaces implemented by JavaScript typed arrays:
|
||||
/// <para>
|
||||
/// <list type="table">
|
||||
/// <listheader>
|
||||
/// <term>Typed Array</term>
|
||||
/// <term>Interface(s) (C#)</term>
|
||||
/// </listheader>
|
||||
/// <item>
|
||||
/// <term><see href="https://msdn.microsoft.com/en-us/library/br212477(v=vs.94).aspx">Uint8Array</see></term>
|
||||
/// <term><c>ITypedArray<byte></c></term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term><see href="https://msdn.microsoft.com/en-us/library/dn641188(v=vs.94).aspx">Uint8ClampedArray</see></term>
|
||||
/// <term><c>ITypedArray<byte></c></term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term><see href="https://msdn.microsoft.com/en-us/library/br212462(v=vs.94).aspx">Int8Array</see></term>
|
||||
/// <term><c>ITypedArray<sbyte></c></term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term><see href="https://msdn.microsoft.com/en-us/library/br212484(v=vs.94).aspx">Uint16Array</see></term>
|
||||
/// <term><c>ITypedArray<ushort></c> and <c>ITypedArray<char></c></term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term><see href="https://msdn.microsoft.com/en-us/library/br212480(v=vs.94).aspx">Int16Array</see></term>
|
||||
/// <term><c>ITypedArray<short></c></term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term><see href="https://msdn.microsoft.com/en-us/library/br230737(v=vs.94).aspx">Uint32Array</see></term>
|
||||
/// <term><c>ITypedArray<uint></c></term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term><see href="https://msdn.microsoft.com/en-us/library/br212468(v=vs.94).aspx">Int32Array</see></term>
|
||||
/// <term><c>ITypedArray<int></c></term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term><see href="https://msdn.microsoft.com/en-us/library/br212916(v=vs.94).aspx">Float32Array</see></term>
|
||||
/// <term><c>ITypedArray<float></c></term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term><see href="https://msdn.microsoft.com/en-us/library/br212931(v=vs.94).aspx">Float64Array</see></term>
|
||||
/// <term><c>ITypedArray<double></c></term>
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public interface ITypedArray<T> : ITypedArray
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an array containing a copy of the typed array's contents.
|
||||
/// </summary>
|
||||
/// <returns>A new array containing a copy of the typed array's contents.</returns>
|
||||
T[] ToArray();
|
||||
|
||||
/// <summary>
|
||||
/// Copies elements from the typed array into the specified array.
|
||||
/// </summary>
|
||||
/// <param name="index">The index within the typed array of the first element to copy.</param>
|
||||
/// <param name="length">The maximum number of elements to copy.</param>
|
||||
/// <param name="destination">The array into which to copy the elements.</param>
|
||||
/// <param name="destinationIndex">The index within <paramref name="destination"/> at which to store the first copied element.</param>
|
||||
/// <returns>The number of elements copied.</returns>
|
||||
ulong Read(ulong index, ulong length, T[] destination, ulong destinationIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Copies elements from the specified array into the typed array.
|
||||
/// </summary>
|
||||
/// <param name="source">The array from which to copy the elements.</param>
|
||||
/// <param name="sourceIndex">The index within <paramref name="source"/> of the first element to copy.</param>
|
||||
/// <param name="length">The maximum number of elements to copy.</param>
|
||||
/// <param name="index">The index within the typed array at which to store the first copied element.</param>
|
||||
/// <returns>The number of elements copied.</returns>
|
||||
ulong Write(T[] source, ulong sourceIndex, ulong length, ulong index);
|
||||
}
|
||||
}
|
|
@ -75,5 +75,5 @@ using System.Runtime.InteropServices;
|
|||
[assembly: InternalsVisibleTo("ClearScriptTest")]
|
||||
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: AssemblyVersion("5.4.3.0")]
|
||||
[assembly: AssemblyFileVersion("5.4.3.0")]
|
||||
[assembly: AssemblyVersion("5.4.4.0")]
|
||||
[assembly: AssemblyFileVersion("5.4.4.0")]
|
||||
|
|
|
@ -335,7 +335,7 @@ namespace Microsoft.ClearScript
|
|||
return GetProperty(index);
|
||||
}
|
||||
|
||||
return GetProperty(name);
|
||||
return GetProperty(name, args);
|
||||
}
|
||||
|
||||
if (invokeFlags.HasFlag(BindingFlags.SetField))
|
||||
|
@ -354,7 +354,7 @@ namespace Microsoft.ClearScript
|
|||
return value;
|
||||
}
|
||||
|
||||
SetProperty(name, value);
|
||||
SetProperty(name, args);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -394,18 +394,18 @@ namespace Microsoft.ClearScript
|
|||
|
||||
#region IDynamic implementation
|
||||
|
||||
public object GetProperty(string name, out bool isCacheable)
|
||||
public object GetProperty(string name, object[] args, out bool isCacheable)
|
||||
{
|
||||
isCacheable = false;
|
||||
return GetProperty(name);
|
||||
return GetProperty(name, args);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDynamic implementation (abstract)
|
||||
|
||||
public abstract object GetProperty(string name);
|
||||
public abstract void SetProperty(string name, object value);
|
||||
public abstract object GetProperty(string name, object[] args);
|
||||
public abstract void SetProperty(string name, object[] args);
|
||||
public abstract bool DeleteProperty(string name);
|
||||
public abstract string[] GetPropertyNames();
|
||||
public abstract object GetProperty(int index);
|
||||
|
|
|
@ -218,7 +218,8 @@ namespace Microsoft.ClearScript.Util
|
|||
[In] [Optional] [MarshalAs(UnmanagedType.Interface)] IServiceProvider svpCaller
|
||||
);
|
||||
|
||||
void DeleteMemberByName(
|
||||
[PreserveSig]
|
||||
int DeleteMemberByName(
|
||||
[In] [MarshalAs(UnmanagedType.BStr)] string name,
|
||||
[In] DispatchNameFlags flags
|
||||
);
|
||||
|
@ -233,12 +234,14 @@ namespace Microsoft.ClearScript.Util
|
|||
[Out] out DispatchPropFlags flags
|
||||
);
|
||||
|
||||
void GetMemberName(
|
||||
[PreserveSig]
|
||||
int GetMemberName(
|
||||
[In] int dispid,
|
||||
[Out] [MarshalAs(UnmanagedType.BStr)] out string name
|
||||
);
|
||||
|
||||
void GetNextDispID(
|
||||
[PreserveSig]
|
||||
int GetNextDispID(
|
||||
[In] DispatchEnumFlags flags,
|
||||
[In] int dispidCurrent,
|
||||
[Out] out int dispidNext
|
||||
|
|
|
@ -60,6 +60,9 @@
|
|||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using DISPPARAMS = System.Runtime.InteropServices.ComTypes.DISPPARAMS;
|
||||
using EXCEPINFO = System.Runtime.InteropServices.ComTypes.EXCEPINFO;
|
||||
|
@ -112,7 +115,28 @@ namespace Microsoft.ClearScript.Util
|
|||
}
|
||||
}
|
||||
|
||||
public static object Invoke(this IDispatchEx dispatchEx, object[] args)
|
||||
public static bool DeleteProperty(this IDispatchEx dispatchEx, string name, bool ignoreCase)
|
||||
{
|
||||
return dispatchEx.DeleteMemberByName(name, ignoreCase ? DispatchNameFlags.CaseInsensitive : DispatchNameFlags.CaseSensitive) == RawCOMHelpers.HResult.S_OK;
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetPropertyNames(this IDispatchEx dispatchEx)
|
||||
{
|
||||
int dispid;
|
||||
var result = dispatchEx.GetNextDispID(DispatchEnumFlags.All, SpecialDispIDs.StartEnum, out dispid);
|
||||
while (result == RawCOMHelpers.HResult.S_OK)
|
||||
{
|
||||
string name;
|
||||
if (dispatchEx.GetMemberName(dispid, out name) == RawCOMHelpers.HResult.S_OK)
|
||||
{
|
||||
yield return name;
|
||||
}
|
||||
|
||||
result = dispatchEx.GetNextDispID(DispatchEnumFlags.All, dispid, out dispid);
|
||||
}
|
||||
}
|
||||
|
||||
public static object Invoke(this IDispatchEx dispatchEx, object[] args, bool asConstructor)
|
||||
{
|
||||
using (var argVariantArrayBlock = new CoTaskMemVariantArgsByRefBlock(args))
|
||||
{
|
||||
|
@ -120,7 +144,7 @@ namespace Microsoft.ClearScript.Util
|
|||
{
|
||||
EXCEPINFO excepInfo;
|
||||
var dispArgs = new DISPPARAMS { cArgs = args.Length, rgvarg = argVariantArrayBlock.Addr, cNamedArgs = 0, rgdispidNamedArgs = IntPtr.Zero };
|
||||
dispatchEx.InvokeEx(SpecialDispIDs.Default, 0, DispatchFlags.Method, ref dispArgs, resultVariantBlock.Addr, out excepInfo);
|
||||
dispatchEx.InvokeEx(SpecialDispIDs.Default, 0, asConstructor ? DispatchFlags.Construct : DispatchFlags.Method, ref dispArgs, resultVariantBlock.Addr, out excepInfo);
|
||||
return Marshal.GetObjectForNativeVariant(resultVariantBlock.Addr);
|
||||
}
|
||||
}
|
||||
|
@ -143,4 +167,71 @@ namespace Microsoft.ClearScript.Util
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class DynamicDispatchExWrapper : IDynamic
|
||||
{
|
||||
private readonly IDispatchEx dispatchEx;
|
||||
|
||||
public DynamicDispatchExWrapper(IDispatchEx dispatchEx)
|
||||
{
|
||||
this.dispatchEx = dispatchEx;
|
||||
}
|
||||
|
||||
public object GetProperty(string name, object[] args)
|
||||
{
|
||||
bool isCacheable;
|
||||
return GetProperty(name, args, out isCacheable);
|
||||
}
|
||||
|
||||
public object GetProperty(string name, object[] args, out bool isCacheable)
|
||||
{
|
||||
isCacheable = false;
|
||||
return dispatchEx.GetProperty(name, false, args);
|
||||
}
|
||||
|
||||
public void SetProperty(string name, object[] args)
|
||||
{
|
||||
dispatchEx.SetProperty(name, false, args);
|
||||
}
|
||||
|
||||
public bool DeleteProperty(string name)
|
||||
{
|
||||
return dispatchEx.DeleteProperty(name, false);
|
||||
}
|
||||
|
||||
public string[] GetPropertyNames()
|
||||
{
|
||||
return dispatchEx.GetPropertyNames().ExcludeIndices().ToArray();
|
||||
}
|
||||
|
||||
public object GetProperty(int index)
|
||||
{
|
||||
return dispatchEx.GetProperty(index.ToString(CultureInfo.InvariantCulture), false, MiscHelpers.GetEmptyArray<object>());
|
||||
}
|
||||
|
||||
public void SetProperty(int index, object value)
|
||||
{
|
||||
dispatchEx.SetProperty(index.ToString(CultureInfo.InvariantCulture), false, new[] { value });
|
||||
}
|
||||
|
||||
public bool DeleteProperty(int index)
|
||||
{
|
||||
return dispatchEx.DeleteProperty(index.ToString(CultureInfo.InvariantCulture), false);
|
||||
}
|
||||
|
||||
public int[] GetPropertyIndices()
|
||||
{
|
||||
return dispatchEx.GetPropertyNames().GetIndices().ToArray();
|
||||
}
|
||||
|
||||
public object Invoke(object[] args, bool asConstructor)
|
||||
{
|
||||
return dispatchEx.Invoke(args, asConstructor);
|
||||
}
|
||||
|
||||
public object InvokeMethod(string name, object[] args)
|
||||
{
|
||||
return dispatchEx.InvokeMethod(name, false, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -223,7 +223,7 @@ namespace Microsoft.ClearScript.Util
|
|||
|
||||
var pArgRef = GetAddrInternal(args.Length - 1 - index);
|
||||
NativeMethods.VariantInit(pArgRef);
|
||||
Marshal.WriteInt16(pArgRef, 0, 0x400C /*VT_BYREF | VT_VARIANT*/);
|
||||
Marshal.WriteInt16(pArgRef, 0, 0x400C /*VT_BYREF|VT_VARIANT*/);
|
||||
Marshal.WriteIntPtr(pArgRef, sizeof(ushort) * 4, pArg);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,44 +123,55 @@ namespace Microsoft.ClearScript.Util
|
|||
}
|
||||
else
|
||||
{
|
||||
var invokeBinder = binder as InvokeBinder;
|
||||
if (invokeBinder != null)
|
||||
var createInstanceBinder = binder as CreateInstanceBinder;
|
||||
if (createInstanceBinder != null)
|
||||
{
|
||||
if (TryInvoke(reflect, args, out result))
|
||||
if (TryCreateInstance(reflect, args, out result))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var invokeMemberBinder = binder as InvokeMemberBinder;
|
||||
if (invokeMemberBinder != null)
|
||||
var invokeBinder = binder as InvokeBinder;
|
||||
if (invokeBinder != null)
|
||||
{
|
||||
if (TryInvokeMethod(reflect, invokeMemberBinder.Name, invokeMemberBinder.IgnoreCase, args, out result))
|
||||
if (TryInvoke(reflect, args, out result))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if ((args != null) && (args.Length > 0))
|
||||
else
|
||||
{
|
||||
var getIndexBinder = binder as GetIndexBinder;
|
||||
if (getIndexBinder != null)
|
||||
var invokeMemberBinder = binder as InvokeMemberBinder;
|
||||
if (invokeMemberBinder != null)
|
||||
{
|
||||
if (TryGetProperty(reflect, args[0].ToString(), false, args.Skip(1).ToArray(), out result))
|
||||
if (TryInvokeMethod(reflect, invokeMemberBinder.Name, invokeMemberBinder.IgnoreCase, args, out result))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if ((args != null) && (args.Length > 0))
|
||||
{
|
||||
var setIndexBinder = binder as SetIndexBinder;
|
||||
if (setIndexBinder != null)
|
||||
var getIndexBinder = binder as GetIndexBinder;
|
||||
if (getIndexBinder != null)
|
||||
{
|
||||
if (TrySetProperty(reflect, args[0].ToString(), false, args.Skip(1).ToArray(), out result))
|
||||
if (TryGetProperty(reflect, args[0].ToString(), false, args.Skip(1).ToArray(), out result))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var setIndexBinder = binder as SetIndexBinder;
|
||||
if (setIndexBinder != null)
|
||||
{
|
||||
if (TrySetProperty(reflect, args[0].ToString(), false, args.Skip(1).ToArray(), out result))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -314,6 +325,39 @@ namespace Microsoft.ClearScript.Util
|
|||
return false;
|
||||
}
|
||||
|
||||
private static bool TryCreateInstance(IReflect target, object[] args, out object result)
|
||||
{
|
||||
// ReSharper disable SuspiciousTypeConversion.Global
|
||||
|
||||
var dispatchEx = target as IDispatchEx;
|
||||
if (dispatchEx != null)
|
||||
{
|
||||
// Standard IExpando-over-IDispatchEx support appears to leak the variants it
|
||||
// creates for the invocation arguments. This issue has been reported. In the
|
||||
// meantime we'll bypass this facility and interface with IDispatchEx directly.
|
||||
|
||||
result = dispatchEx.Invoke(args, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ReSharper restore SuspiciousTypeConversion.Global
|
||||
|
||||
try
|
||||
{
|
||||
result = target.InvokeMember(SpecialMemberNames.Default, BindingFlags.CreateInstance, null, target, args, null, CultureInfo.InvariantCulture, null);
|
||||
return true;
|
||||
}
|
||||
catch (TargetInvocationException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryInvoke(IReflect target, object[] args, out object result)
|
||||
{
|
||||
// ReSharper disable SuspiciousTypeConversion.Global
|
||||
|
@ -325,14 +369,26 @@ namespace Microsoft.ClearScript.Util
|
|||
// creates for the invocation arguments. This issue has been reported. In the
|
||||
// meantime we'll bypass this facility and interface with IDispatchEx directly.
|
||||
|
||||
result = dispatchEx.Invoke(args);
|
||||
result = dispatchEx.Invoke(args, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ReSharper restore SuspiciousTypeConversion.Global
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
try
|
||||
{
|
||||
result = target.InvokeMember(SpecialMemberNames.Default, BindingFlags.InvokeMethod, null, target, args, null, CultureInfo.InvariantCulture, null);
|
||||
return true;
|
||||
}
|
||||
catch (TargetInvocationException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryInvokeMethod(IReflect target, string name, bool ignoreCase, object[] args, out object result)
|
||||
|
|
|
@ -63,9 +63,9 @@ namespace Microsoft.ClearScript.Util
|
|||
{
|
||||
internal interface IDynamic
|
||||
{
|
||||
object GetProperty(string name);
|
||||
object GetProperty(string name, out bool isCacheable);
|
||||
void SetProperty(string name, object value);
|
||||
object GetProperty(string name, object[] args);
|
||||
object GetProperty(string name, object[] args, out bool isCacheable);
|
||||
void SetProperty(string name, object[] args);
|
||||
bool DeleteProperty(string name);
|
||||
string[] GetPropertyNames();
|
||||
|
||||
|
|
|
@ -83,17 +83,18 @@ namespace Microsoft.ClearScript.Util
|
|||
{
|
||||
if ((index != (args.Length - 1)) || !param.ParameterType.IsInstanceOfType(args[index]))
|
||||
{
|
||||
var tailArgs = Array.CreateInstance(param.ParameterType.GetElementType(), args.Length - index);
|
||||
var tailArgType = param.ParameterType.GetElementType();
|
||||
var tailArgs = Array.CreateInstance(tailArgType, args.Length - index);
|
||||
for (var innerIndex = index; innerIndex < args.Length; innerIndex++)
|
||||
{
|
||||
var byRefArg = args[innerIndex] as IByRefArg;
|
||||
if (byRefArg == null)
|
||||
{
|
||||
tailArgs.SetValue(args[innerIndex], innerIndex - index);
|
||||
tailArgs.SetValue(GetCompatibleArg(param.Name, tailArgType, args[innerIndex]), innerIndex - index);
|
||||
}
|
||||
else
|
||||
{
|
||||
tailArgs.SetValue(byRefArg.Value, innerIndex - index);
|
||||
tailArgs.SetValue(GetCompatibleArg(param.Name, tailArgType, byRefArg.Value), innerIndex - index);
|
||||
byRefArgInfo.Add(new ByRefArgItem(byRefArg, tailArgs, innerIndex - index));
|
||||
}
|
||||
}
|
||||
|
@ -109,11 +110,11 @@ namespace Microsoft.ClearScript.Util
|
|||
var byRefArg = args[index] as IByRefArg;
|
||||
if (byRefArg == null)
|
||||
{
|
||||
argList.Add(args[index]);
|
||||
argList.Add(GetCompatibleArg(param, args[index]));
|
||||
}
|
||||
else
|
||||
{
|
||||
argList.Add(byRefArg.Value);
|
||||
argList.Add(GetCompatibleArg(param, byRefArg.Value));
|
||||
byRefArgInfo.Add(new ByRefArgItem(byRefArg, null, index));
|
||||
}
|
||||
}
|
||||
|
@ -232,6 +233,21 @@ namespace Microsoft.ClearScript.Util
|
|||
return false;
|
||||
}
|
||||
|
||||
private static object GetCompatibleArg(ParameterInfo param, object value)
|
||||
{
|
||||
return GetCompatibleArg(param.Name, param.ParameterType, value);
|
||||
}
|
||||
|
||||
private static object GetCompatibleArg(string paramName, Type type, object value)
|
||||
{
|
||||
if (!type.IsAssignableFrom(ref value))
|
||||
{
|
||||
throw new ArgumentException(MiscHelpers.FormatInvariant("Invalid argument specified for parameter '{0}'", paramName));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
#region Nested type: ByRefArgItem
|
||||
|
||||
private class ByRefArgItem
|
||||
|
|
|
@ -355,11 +355,28 @@ namespace Microsoft.ClearScript.Util
|
|||
|
||||
public static T Exchange<T>(ref T target, T value)
|
||||
{
|
||||
T oldValue = target;
|
||||
var oldValue = target;
|
||||
target = value;
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
public static bool IsX86InstructionSet()
|
||||
{
|
||||
SystemInfo info;
|
||||
try
|
||||
{
|
||||
NativeMethods.GetNativeSystemInfo(out info);
|
||||
}
|
||||
catch (EntryPointNotFoundException)
|
||||
{
|
||||
NativeMethods.GetSystemInfo(out info);
|
||||
}
|
||||
|
||||
return
|
||||
((info.ProcessorArchitecture == 0 /*PROCESSOR_ARCHITECTURE_INTEL*/) ||
|
||||
(info.ProcessorArchitecture == 9 /*PROCESSOR_ARCHITECTURE_AMD64*/));
|
||||
}
|
||||
|
||||
#region Nested type: EmptyArray<T>
|
||||
|
||||
private static class EmptyArray<T>
|
||||
|
|
|
@ -64,6 +64,22 @@ using System.Runtime.InteropServices;
|
|||
|
||||
namespace Microsoft.ClearScript.Util
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct SystemInfo
|
||||
{
|
||||
public ushort ProcessorArchitecture;
|
||||
public ushort Reserved;
|
||||
public uint PageSize;
|
||||
public IntPtr MinimumApplicationAddress;
|
||||
public IntPtr MaximumApplicationAddress;
|
||||
public IntPtr ActiveProcessorMask;
|
||||
public uint NumberOfProcessors;
|
||||
public uint ProcessorType;
|
||||
public uint AllocationGranularity;
|
||||
public ushort ProcessorLevel;
|
||||
public ushort ProcessorRevision;
|
||||
}
|
||||
|
||||
internal static class NativeMethods
|
||||
{
|
||||
[DllImport("kernel32", ExactSpelling = true, SetLastError = true)]
|
||||
|
@ -99,5 +115,38 @@ namespace Microsoft.ClearScript.Util
|
|||
public static extern uint VariantClear(
|
||||
[In] IntPtr pVariant
|
||||
);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr HeapCreate(
|
||||
[In] uint options,
|
||||
[In] UIntPtr initialSize,
|
||||
[In] UIntPtr maximumSize
|
||||
);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = false)]
|
||||
public static extern IntPtr HeapAlloc(
|
||||
[In] IntPtr hHeap,
|
||||
[In] uint flags,
|
||||
[In] UIntPtr size
|
||||
);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool HeapDestroy(
|
||||
[In] IntPtr hHeap
|
||||
);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool VirtualProtect(
|
||||
[In] IntPtr pBlock,
|
||||
[In] UIntPtr size,
|
||||
[In] uint newProtect,
|
||||
[Out] out uint oldProtect
|
||||
);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = false)]
|
||||
public static extern void GetSystemInfo(out SystemInfo info);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern void GetNativeSystemInfo(out SystemInfo info);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,8 @@ using System.Reflection;
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using TYPEATTR = System.Runtime.InteropServices.ComTypes.TYPEATTR;
|
||||
using TYPEFLAGS = System.Runtime.InteropServices.ComTypes.TYPEFLAGS;
|
||||
using TYPEKIND = System.Runtime.InteropServices.ComTypes.TYPEKIND;
|
||||
using TYPELIBATTR = System.Runtime.InteropServices.ComTypes.TYPELIBATTR;
|
||||
|
||||
namespace Microsoft.ClearScript.Util
|
||||
|
@ -77,14 +79,18 @@ namespace Microsoft.ClearScript.Util
|
|||
public static Type GetTypeOrTypeInfo(this object value)
|
||||
{
|
||||
var type = value.GetType();
|
||||
IDispatch dispatch = null;
|
||||
|
||||
Type typeInfo = null;
|
||||
TYPEKIND typeInfoKind = 0;
|
||||
TYPEFLAGS typeInfoFlags = 0;
|
||||
|
||||
if (type.IsUnknownCOMObject())
|
||||
{
|
||||
// This appears to be a generic COM object with no specific type information.
|
||||
// Attempt to acquire COM type information via IDispatch or IProvideClassInfo.
|
||||
|
||||
var dispatch = value as IDispatch;
|
||||
dispatch = value as IDispatch;
|
||||
if (dispatch != null)
|
||||
{
|
||||
uint count;
|
||||
|
@ -94,6 +100,8 @@ namespace Microsoft.ClearScript.Util
|
|||
if (RawCOMHelpers.HResult.Succeeded(dispatch.GetTypeInfo(0, 0, out tempTypeInfo)))
|
||||
{
|
||||
typeInfo = GetTypeForTypeInfo(tempTypeInfo);
|
||||
typeInfoKind = GetTypeInfoKind(tempTypeInfo);
|
||||
typeInfoFlags = GetTypeInfoFlags(tempTypeInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -107,6 +115,8 @@ namespace Microsoft.ClearScript.Util
|
|||
if (RawCOMHelpers.HResult.Succeeded(provideClassInfo.GetClassInfo(out tempTypeInfo)))
|
||||
{
|
||||
typeInfo = GetTypeForTypeInfo(tempTypeInfo);
|
||||
typeInfoKind = GetTypeInfoKind(tempTypeInfo);
|
||||
typeInfoFlags = GetTypeInfoFlags(tempTypeInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -114,6 +124,14 @@ namespace Microsoft.ClearScript.Util
|
|||
|
||||
if (typeInfo != null)
|
||||
{
|
||||
// If the COM type is a dispatch-only interface, use it. Such interfaces typically
|
||||
// aren't exposed via QueryInterface(), so there's no way to validate them anyway.
|
||||
|
||||
if ((dispatch != null) && (typeInfoKind == TYPEKIND.TKIND_DISPATCH) && typeInfoFlags.HasFlag(TYPEFLAGS.TYPEFLAG_FDISPATCHABLE) && !typeInfoFlags.HasFlag(TYPEFLAGS.TYPEFLAG_FDUAL))
|
||||
{
|
||||
return typeInfo;
|
||||
}
|
||||
|
||||
// COM type information acquired in this manner may not actually be valid for the
|
||||
// original object. In some cases the original object implements a base interface.
|
||||
|
||||
|
@ -209,7 +227,7 @@ namespace Microsoft.ClearScript.Util
|
|||
var name = GetManagedTypeInfoName(typeInfo, typeLib);
|
||||
var guid = GetTypeInfoGuid(typeInfo);
|
||||
|
||||
var type = assembly.GetType(name, false /*throwOnError*/);
|
||||
var type = assembly.GetType(name, false /*throwOnError*/, true /*ignoreCase*/);
|
||||
if ((type != null) && (type.GUID == guid))
|
||||
{
|
||||
return type;
|
||||
|
@ -225,14 +243,14 @@ namespace Microsoft.ClearScript.Util
|
|||
}
|
||||
}
|
||||
|
||||
type = types.FirstOrDefault(testType => (testType.GUID == guid) && (testType.FullName == name));
|
||||
type = types.FirstOrDefault(testType => (testType.GUID == guid) && (testType.FullName.Equals(name, StringComparison.OrdinalIgnoreCase)));
|
||||
if (type != null)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
var pTypeInfo = RawCOMHelpers.QueryInterface<ITypeInfo>(Marshal.GetIUnknownForObject(typeInfo));
|
||||
var pTypeInfo = Marshal.GetComInterfaceForObject(typeInfo, typeof(ITypeInfo));
|
||||
try
|
||||
{
|
||||
return Marshal.GetTypeForITypeInfo(pTypeInfo);
|
||||
|
@ -363,6 +381,36 @@ namespace Microsoft.ClearScript.Util
|
|||
}
|
||||
}
|
||||
|
||||
private static TYPEKIND GetTypeInfoKind(ITypeInfo typeInfo)
|
||||
{
|
||||
IntPtr pAttr;
|
||||
typeInfo.GetTypeAttr(out pAttr);
|
||||
try
|
||||
{
|
||||
var attr = (TYPEATTR)Marshal.PtrToStructure(pAttr, typeof(TYPEATTR));
|
||||
return attr.typekind;
|
||||
}
|
||||
finally
|
||||
{
|
||||
typeInfo.ReleaseTypeAttr(pAttr);
|
||||
}
|
||||
}
|
||||
|
||||
private static TYPEFLAGS GetTypeInfoFlags(ITypeInfo typeInfo)
|
||||
{
|
||||
IntPtr pAttr;
|
||||
typeInfo.GetTypeAttr(out pAttr);
|
||||
try
|
||||
{
|
||||
var attr = (TYPEATTR)Marshal.PtrToStructure(pAttr, typeof(TYPEATTR));
|
||||
return attr.wTypeFlags;
|
||||
}
|
||||
finally
|
||||
{
|
||||
typeInfo.ReleaseTypeAttr(pAttr);
|
||||
}
|
||||
}
|
||||
|
||||
#region Nested type: IProvideClassInfo
|
||||
|
||||
[ComImport]
|
||||
|
|
|
@ -65,6 +65,7 @@ namespace Microsoft.ClearScript.Util
|
|||
{
|
||||
public const int Default = 0;
|
||||
public const int Unknown = -1;
|
||||
public const int StartEnum = Unknown;
|
||||
public const int PropertyPut = -3;
|
||||
public const int NewEnum = -4;
|
||||
public const int This = -613;
|
||||
|
|
|
@ -81,20 +81,6 @@ namespace Microsoft.ClearScript.Util
|
|||
"__DynamicallyInvokableAttribute"
|
||||
};
|
||||
|
||||
private static readonly Dictionary<TypeCode, TypeCode[]> implicitNumericConversions = new Dictionary<TypeCode, TypeCode[]>
|
||||
{
|
||||
{ TypeCode.SByte, new[] { TypeCode.Int16, TypeCode.Int32, TypeCode.Int64, TypeCode.Single, TypeCode.Double, TypeCode.Decimal } },
|
||||
{ TypeCode.Byte, new[] { TypeCode.Int16, TypeCode.UInt16, TypeCode.Int32, TypeCode.UInt32, TypeCode.Int64, TypeCode.UInt64, TypeCode.Single, TypeCode.Double, TypeCode.Decimal } },
|
||||
{ TypeCode.Int16, new[] { TypeCode.Int32, TypeCode.Int64, TypeCode.Single, TypeCode.Double, TypeCode.Decimal } },
|
||||
{ TypeCode.UInt16, new[] { TypeCode.Int32, TypeCode.UInt32, TypeCode.Int64, TypeCode.UInt64, TypeCode.Single, TypeCode.Double, TypeCode.Decimal } },
|
||||
{ TypeCode.Int32, new[] { TypeCode.SByte, TypeCode.Byte, TypeCode.Int16, TypeCode.UInt16, TypeCode.UInt32, TypeCode.Int64, TypeCode.UInt64, TypeCode.Single, TypeCode.Double, TypeCode.Decimal } },
|
||||
{ TypeCode.UInt32, new[] { TypeCode.Int64, TypeCode.UInt64, TypeCode.Single, TypeCode.Double, TypeCode.Decimal } },
|
||||
{ TypeCode.Int64, new[] { TypeCode.Single, TypeCode.Double, TypeCode.Decimal } },
|
||||
{ TypeCode.UInt64, new[] { TypeCode.Single, TypeCode.Double, TypeCode.Decimal } },
|
||||
{ TypeCode.Char, new[] { TypeCode.UInt16, TypeCode.Int32, TypeCode.UInt32, TypeCode.Int64, TypeCode.UInt64, TypeCode.Single, TypeCode.Double, TypeCode.Decimal } },
|
||||
{ TypeCode.Single, new[] { TypeCode.Double } },
|
||||
};
|
||||
|
||||
private static readonly HashSet<Type> nullableNumericTypes = new HashSet<Type>
|
||||
{
|
||||
typeof(char?),
|
||||
|
@ -142,31 +128,40 @@ namespace Microsoft.ClearScript.Util
|
|||
return false;
|
||||
}
|
||||
|
||||
public static bool IsIntegral(this Type type)
|
||||
{
|
||||
return
|
||||
(type == typeof(sbyte)) ||
|
||||
(type == typeof(byte)) ||
|
||||
(type == typeof(short)) ||
|
||||
(type == typeof(ushort)) ||
|
||||
(type == typeof(char)) ||
|
||||
(type == typeof(int)) ||
|
||||
(type == typeof(uint)) ||
|
||||
(type == typeof(long)) ||
|
||||
(type == typeof(ulong));
|
||||
}
|
||||
|
||||
public static bool IsFloatingPoint(this Type type)
|
||||
{
|
||||
return
|
||||
(type == typeof(float)) ||
|
||||
(type == typeof(double));
|
||||
}
|
||||
|
||||
public static bool IsNumeric(this Type type, out bool isIntegral)
|
||||
{
|
||||
isIntegral = type.IsIntegral();
|
||||
return
|
||||
isIntegral ||
|
||||
type.IsFloatingPoint() ||
|
||||
type == typeof(decimal);
|
||||
}
|
||||
|
||||
public static bool IsNumeric(this Type type)
|
||||
{
|
||||
if (type.IsEnum)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (Type.GetTypeCode(type))
|
||||
{
|
||||
case TypeCode.Char:
|
||||
case TypeCode.SByte:
|
||||
case TypeCode.Byte:
|
||||
case TypeCode.Int16:
|
||||
case TypeCode.UInt16:
|
||||
case TypeCode.Int32:
|
||||
case TypeCode.UInt32:
|
||||
case TypeCode.Int64:
|
||||
case TypeCode.UInt64:
|
||||
case TypeCode.Single:
|
||||
case TypeCode.Double:
|
||||
case TypeCode.Decimal:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
bool isIntegral;
|
||||
return type.IsNumeric(out isIntegral);
|
||||
}
|
||||
|
||||
public static bool IsNullable(this Type type)
|
||||
|
@ -227,15 +222,23 @@ namespace Microsoft.ClearScript.Util
|
|||
return false;
|
||||
}
|
||||
|
||||
TypeCode[] typeCodes;
|
||||
if (implicitNumericConversions.TryGetValue(Type.GetTypeCode(valueType), out typeCodes))
|
||||
bool typeIsIntegral;
|
||||
if (type.IsNumeric(out typeIsIntegral))
|
||||
{
|
||||
var typeCode = Type.GetTypeCode(type);
|
||||
if (typeCodes.Contains(Type.GetTypeCode(type)))
|
||||
if (typeIsIntegral)
|
||||
{
|
||||
value = Convert.ChangeType(value, typeCode);
|
||||
return true;
|
||||
if (!valueType.IsIntegral())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!valueType.IsNumeric())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
value = Convert.ChangeType(value, type);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -451,7 +454,7 @@ namespace Microsoft.ClearScript.Util
|
|||
|
||||
// ReSharper disable RedundantEnumerableCastCall
|
||||
|
||||
// the OfType<>() call is not redundant; it filters out null elements
|
||||
// the OfType<Type>() call is not redundant; it filters out null elements
|
||||
var counts = Enumerable.Range(1, maxTypeArgCount);
|
||||
var templates = counts.Select(count => ImportType(typeName, assemblyName, useAssemblyName, count)).OfType<Type>().ToArray();
|
||||
|
||||
|
|
|
@ -0,0 +1,655 @@
|
|||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.ClearScript.Util
|
||||
{
|
||||
internal static class UnmanagedMemoryHelpers
|
||||
{
|
||||
private delegate ulong ReadArrayFromUnmanagedMemoryHandler(IntPtr pSource, ulong length, Array destinationArray, ulong destinationIndex);
|
||||
private delegate ulong WriteArrayToUnmanagedMemoryHandler(Array sourceArray, ulong sourceIndex, ulong length, IntPtr pDestination);
|
||||
|
||||
private static readonly Dictionary<Type, ReadArrayFromUnmanagedMemoryHandler> readArrayFromUnmanagedMemoryHandlerMap = new Dictionary<Type, ReadArrayFromUnmanagedMemoryHandler>
|
||||
{
|
||||
{ typeof(byte), ReadByteArrayFromUnmanagedMemory },
|
||||
{ typeof(sbyte), ReadSByteArrayFromUnmanagedMemory },
|
||||
{ typeof(ushort), ReadUInt16ArrayFromUnmanagedMemory },
|
||||
{ typeof(char), ReadCharArrayFromUnmanagedMemory },
|
||||
{ typeof(short), ReadInt16ArrayFromUnmanagedMemory },
|
||||
{ typeof(uint), ReadUInt32ArrayFromUnmanagedMemory },
|
||||
{ typeof(int), ReadInt32ArrayFromUnmanagedMemory },
|
||||
{ typeof(float), ReadSingleArrayFromUnmanagedMemory },
|
||||
{ typeof(double), ReadDoubleArrayFromUnmanagedMemory }
|
||||
};
|
||||
|
||||
private static readonly Dictionary<Type, WriteArrayToUnmanagedMemoryHandler> writeArrayToUnmanagedMemoryHandlerMap = new Dictionary<Type, WriteArrayToUnmanagedMemoryHandler>
|
||||
{
|
||||
{ typeof(byte), WriteByteArrayToUnmanagedMemory },
|
||||
{ typeof(sbyte), WriteSByteArrayToUnmanagedMemory },
|
||||
{ typeof(ushort), WriteUInt16ArrayToUnmanagedMemory },
|
||||
{ typeof(char), WriteCharArrayToUnmanagedMemory },
|
||||
{ typeof(short), WriteInt16ArrayToUnmanagedMemory },
|
||||
{ typeof(uint), WriteUInt32ArrayToUnmanagedMemory },
|
||||
{ typeof(int), WriteInt32ArrayToUnmanagedMemory },
|
||||
{ typeof(float), WriteSingleArrayToUnmanagedMemory },
|
||||
{ typeof(double), WriteDoubleArrayToUnmanagedMemory }
|
||||
};
|
||||
|
||||
public static ulong Copy<T>(IntPtr pSource, ulong length, T[] destination, ulong destinationIndex)
|
||||
{
|
||||
return Copy(typeof(T), pSource, length, destination, destinationIndex);
|
||||
}
|
||||
|
||||
public static ulong Copy<T>(T[] source, ulong sourceIndex, ulong length, IntPtr pDestination)
|
||||
{
|
||||
return Copy(typeof(T), source, sourceIndex, length, pDestination);
|
||||
}
|
||||
|
||||
private static ulong Copy(Type type, IntPtr pSource, ulong length, Array destinationArray, ulong destinationIndex)
|
||||
{
|
||||
ReadArrayFromUnmanagedMemoryHandler handler;
|
||||
if (readArrayFromUnmanagedMemoryHandlerMap.TryGetValue(type, out handler))
|
||||
{
|
||||
return handler(pSource, length, destinationArray, destinationIndex);
|
||||
}
|
||||
|
||||
throw new NotSupportedException("Unsupported unmanaged data transfer operation");
|
||||
}
|
||||
|
||||
private static ulong Copy(Type type, Array sourceArray, ulong sourceIndex, ulong length, IntPtr pDestination)
|
||||
{
|
||||
WriteArrayToUnmanagedMemoryHandler handler;
|
||||
if (writeArrayToUnmanagedMemoryHandlerMap.TryGetValue(type, out handler))
|
||||
{
|
||||
return handler(sourceArray, sourceIndex, length, pDestination);
|
||||
}
|
||||
|
||||
throw new NotSupportedException("Unsupported unmanaged data transfer operation");
|
||||
}
|
||||
|
||||
private static unsafe ulong ReadByteArrayFromUnmanagedMemory(IntPtr pSource, ulong length, Array destinationArray, ulong destinationIndex)
|
||||
{
|
||||
var destinationLength = (ulong)destinationArray.LongLength;
|
||||
if (destinationIndex >= destinationLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("destinationIndex");
|
||||
}
|
||||
|
||||
var destination = (byte[])destinationArray;
|
||||
length = Math.Min(length, destinationLength - destinationIndex);
|
||||
|
||||
try
|
||||
{
|
||||
VerifyMarshalCopyEnabled();
|
||||
Marshal.Copy(pSource, destination, Convert.ToInt32(destinationIndex), Convert.ToInt32(length));
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
fixed (byte* pDest = destination)
|
||||
{
|
||||
var pSrc = (byte*)pSource;
|
||||
for (var index = 0UL; index < length; index++)
|
||||
{
|
||||
pDest[destinationIndex + index] = pSrc[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static unsafe ulong ReadSByteArrayFromUnmanagedMemory(IntPtr pSource, ulong length, Array destinationArray, ulong destinationIndex)
|
||||
{
|
||||
var destinationLength = (ulong)destinationArray.LongLength;
|
||||
if (destinationIndex >= destinationLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("destinationIndex");
|
||||
}
|
||||
|
||||
var destination = (sbyte[])destinationArray;
|
||||
length = Math.Min(length, destinationLength - destinationIndex);
|
||||
|
||||
fixed (sbyte* pDest = destination)
|
||||
{
|
||||
var pSrc = (sbyte*)pSource;
|
||||
for (var index = 0UL; index < length; index++)
|
||||
{
|
||||
pDest[destinationIndex + index] = pSrc[index];
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static unsafe ulong ReadUInt16ArrayFromUnmanagedMemory(IntPtr pSource, ulong length, Array destinationArray, ulong destinationIndex)
|
||||
{
|
||||
var destinationLength = (ulong)destinationArray.LongLength;
|
||||
if (destinationIndex >= destinationLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("destinationIndex");
|
||||
}
|
||||
|
||||
var destination = (ushort[])destinationArray;
|
||||
length = Math.Min(length, destinationLength - destinationIndex);
|
||||
|
||||
fixed (ushort* pDest = destination)
|
||||
{
|
||||
var pSrc = (ushort*)pSource;
|
||||
for (var index = 0UL; index < length; index++)
|
||||
{
|
||||
pDest[destinationIndex + index] = pSrc[index];
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static unsafe ulong ReadCharArrayFromUnmanagedMemory(IntPtr pSource, ulong length, Array destinationArray, ulong destinationIndex)
|
||||
{
|
||||
var destinationLength = (ulong)destinationArray.LongLength;
|
||||
if (destinationIndex >= destinationLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("destinationIndex");
|
||||
}
|
||||
|
||||
var destination = (char[])destinationArray;
|
||||
length = Math.Min(length, destinationLength - destinationIndex);
|
||||
|
||||
try
|
||||
{
|
||||
VerifyMarshalCopyEnabled();
|
||||
Marshal.Copy(pSource, destination, Convert.ToInt32(destinationIndex), Convert.ToInt32(length));
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
fixed (char* pDest = destination)
|
||||
{
|
||||
var pSrc = (char*)pSource;
|
||||
for (var index = 0UL; index < length; index++)
|
||||
{
|
||||
pDest[destinationIndex + index] = pSrc[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static unsafe ulong ReadInt16ArrayFromUnmanagedMemory(IntPtr pSource, ulong length, Array destinationArray, ulong destinationIndex)
|
||||
{
|
||||
var destinationLength = (ulong)destinationArray.LongLength;
|
||||
if (destinationIndex >= destinationLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("destinationIndex");
|
||||
}
|
||||
|
||||
var destination = (short[])destinationArray;
|
||||
length = Math.Min(length, destinationLength - destinationIndex);
|
||||
|
||||
try
|
||||
{
|
||||
VerifyMarshalCopyEnabled();
|
||||
Marshal.Copy(pSource, destination, Convert.ToInt32(destinationIndex), Convert.ToInt32(length));
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
fixed (short* pDest = destination)
|
||||
{
|
||||
var pSrc = (short*)pSource;
|
||||
for (var index = 0UL; index < length; index++)
|
||||
{
|
||||
pDest[destinationIndex + index] = pSrc[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static unsafe ulong ReadUInt32ArrayFromUnmanagedMemory(IntPtr pSource, ulong length, Array destinationArray, ulong destinationIndex)
|
||||
{
|
||||
var destinationLength = (ulong)destinationArray.LongLength;
|
||||
if (destinationIndex >= destinationLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("destinationIndex");
|
||||
}
|
||||
|
||||
var destination = (uint[])destinationArray;
|
||||
length = Math.Min(length, destinationLength - destinationIndex);
|
||||
|
||||
fixed (uint* pDest = destination)
|
||||
{
|
||||
var pSrc = (uint*)pSource;
|
||||
for (var index = 0UL; index < length; index++)
|
||||
{
|
||||
pDest[destinationIndex + index] = pSrc[index];
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static unsafe ulong ReadInt32ArrayFromUnmanagedMemory(IntPtr pSource, ulong length, Array destinationArray, ulong destinationIndex)
|
||||
{
|
||||
var destinationLength = (ulong)destinationArray.LongLength;
|
||||
if (destinationIndex >= destinationLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("destinationIndex");
|
||||
}
|
||||
|
||||
var destination = (int[])destinationArray;
|
||||
length = Math.Min(length, destinationLength - destinationIndex);
|
||||
|
||||
try
|
||||
{
|
||||
VerifyMarshalCopyEnabled();
|
||||
Marshal.Copy(pSource, destination, Convert.ToInt32(destinationIndex), Convert.ToInt32(length));
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
fixed (int* pDest = destination)
|
||||
{
|
||||
var pSrc = (int*)pSource;
|
||||
for (var index = 0UL; index < length; index++)
|
||||
{
|
||||
pDest[destinationIndex + index] = pSrc[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static unsafe ulong ReadSingleArrayFromUnmanagedMemory(IntPtr pSource, ulong length, Array destinationArray, ulong destinationIndex)
|
||||
{
|
||||
var destinationLength = (ulong)destinationArray.LongLength;
|
||||
if (destinationIndex >= destinationLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("destinationIndex");
|
||||
}
|
||||
|
||||
var destination = (float[])destinationArray;
|
||||
length = Math.Min(length, destinationLength - destinationIndex);
|
||||
|
||||
try
|
||||
{
|
||||
VerifyMarshalCopyEnabled();
|
||||
Marshal.Copy(pSource, destination, Convert.ToInt32(destinationIndex), Convert.ToInt32(length));
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
fixed (float* pDest = destination)
|
||||
{
|
||||
var pSrc = (float*)pSource;
|
||||
for (var index = 0UL; index < length; index++)
|
||||
{
|
||||
pDest[destinationIndex + index] = pSrc[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static unsafe ulong ReadDoubleArrayFromUnmanagedMemory(IntPtr pSource, ulong length, Array destinationArray, ulong destinationIndex)
|
||||
{
|
||||
var destinationLength = (ulong)destinationArray.LongLength;
|
||||
if (destinationIndex >= destinationLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("destinationIndex");
|
||||
}
|
||||
|
||||
var destination = (double[])destinationArray;
|
||||
length = Math.Min(length, destinationLength - destinationIndex);
|
||||
|
||||
try
|
||||
{
|
||||
VerifyMarshalCopyEnabled();
|
||||
Marshal.Copy(pSource, destination, Convert.ToInt32(destinationIndex), Convert.ToInt32(length));
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
fixed (double* pDest = destination)
|
||||
{
|
||||
var pSrc = (double*)pSource;
|
||||
for (var index = 0UL; index < length; index++)
|
||||
{
|
||||
pDest[destinationIndex + index] = pSrc[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static unsafe ulong WriteByteArrayToUnmanagedMemory(Array sourceArray, ulong sourceIndex, ulong length, IntPtr pDestination)
|
||||
{
|
||||
var sourceLength = (ulong)sourceArray.LongLength;
|
||||
if (sourceIndex >= sourceLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("sourceIndex");
|
||||
}
|
||||
|
||||
var source = (byte[])sourceArray;
|
||||
length = Math.Min(length, sourceLength - sourceIndex);
|
||||
|
||||
try
|
||||
{
|
||||
VerifyMarshalCopyEnabled();
|
||||
Marshal.Copy(source, Convert.ToInt32(sourceIndex), pDestination, Convert.ToInt32(length));
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
fixed (byte* pSrc = source)
|
||||
{
|
||||
var pDest = (byte*)pDestination;
|
||||
for (var index = 0UL; index < length; index++)
|
||||
{
|
||||
pDest[index] = pSrc[sourceIndex + index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static unsafe ulong WriteSByteArrayToUnmanagedMemory(Array sourceArray, ulong sourceIndex, ulong length, IntPtr pDestination)
|
||||
{
|
||||
var sourceLength = (ulong)sourceArray.LongLength;
|
||||
if (sourceIndex >= sourceLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("sourceIndex");
|
||||
}
|
||||
|
||||
var source = (sbyte[])sourceArray;
|
||||
length = Math.Min(length, sourceLength - sourceIndex);
|
||||
|
||||
fixed (sbyte* pSrc = source)
|
||||
{
|
||||
var pDest = (sbyte*)pDestination;
|
||||
for (var index = 0UL; index < length; index++)
|
||||
{
|
||||
pDest[index] = pSrc[sourceIndex + index];
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static unsafe ulong WriteUInt16ArrayToUnmanagedMemory(Array sourceArray, ulong sourceIndex, ulong length, IntPtr pDestination)
|
||||
{
|
||||
var sourceLength = (ulong)sourceArray.LongLength;
|
||||
if (sourceIndex >= sourceLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("sourceIndex");
|
||||
}
|
||||
|
||||
var source = (ushort[])sourceArray;
|
||||
length = Math.Min(length, sourceLength - sourceIndex);
|
||||
|
||||
fixed (ushort* pSrc = source)
|
||||
{
|
||||
var pDest = (ushort*)pDestination;
|
||||
for (var index = 0UL; index < length; index++)
|
||||
{
|
||||
pDest[index] = pSrc[sourceIndex + index];
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static unsafe ulong WriteCharArrayToUnmanagedMemory(Array sourceArray, ulong sourceIndex, ulong length, IntPtr pDestination)
|
||||
{
|
||||
var sourceLength = (ulong)sourceArray.LongLength;
|
||||
if (sourceIndex >= sourceLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("sourceIndex");
|
||||
}
|
||||
|
||||
var source = (char[])sourceArray;
|
||||
length = Math.Min(length, sourceLength - sourceIndex);
|
||||
|
||||
try
|
||||
{
|
||||
VerifyMarshalCopyEnabled();
|
||||
Marshal.Copy(source, Convert.ToInt32(sourceIndex), pDestination, Convert.ToInt32(length));
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
fixed (char* pSrc = source)
|
||||
{
|
||||
var pDest = (char*)pDestination;
|
||||
for (var index = 0UL; index < length; index++)
|
||||
{
|
||||
pDest[index] = pSrc[sourceIndex + index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static unsafe ulong WriteInt16ArrayToUnmanagedMemory(Array sourceArray, ulong sourceIndex, ulong length, IntPtr pDestination)
|
||||
{
|
||||
var sourceLength = (ulong)sourceArray.LongLength;
|
||||
if (sourceIndex >= sourceLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("sourceIndex");
|
||||
}
|
||||
|
||||
var source = (short[])sourceArray;
|
||||
length = Math.Min(length, sourceLength - sourceIndex);
|
||||
|
||||
try
|
||||
{
|
||||
VerifyMarshalCopyEnabled();
|
||||
Marshal.Copy(source, Convert.ToInt32(sourceIndex), pDestination, Convert.ToInt32(length));
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
fixed (short* pSrc = source)
|
||||
{
|
||||
var pDest = (short*)pDestination;
|
||||
for (var index = 0UL; index < length; index++)
|
||||
{
|
||||
pDest[index] = pSrc[sourceIndex + index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static unsafe ulong WriteUInt32ArrayToUnmanagedMemory(Array sourceArray, ulong sourceIndex, ulong length, IntPtr pDestination)
|
||||
{
|
||||
var sourceLength = (ulong)sourceArray.LongLength;
|
||||
if (sourceIndex >= sourceLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("sourceIndex");
|
||||
}
|
||||
|
||||
var source = (uint[])sourceArray;
|
||||
length = Math.Min(length, sourceLength - sourceIndex);
|
||||
|
||||
fixed (uint* pSrc = source)
|
||||
{
|
||||
var pDest = (uint*)pDestination;
|
||||
for (var index = 0UL; index < length; index++)
|
||||
{
|
||||
pDest[index] = pSrc[sourceIndex + index];
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static unsafe ulong WriteInt32ArrayToUnmanagedMemory(Array sourceArray, ulong sourceIndex, ulong length, IntPtr pDestination)
|
||||
{
|
||||
var sourceLength = (ulong)sourceArray.LongLength;
|
||||
if (sourceIndex >= sourceLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("sourceIndex");
|
||||
}
|
||||
|
||||
var source = (int[])sourceArray;
|
||||
length = Math.Min(length, sourceLength - sourceIndex);
|
||||
|
||||
try
|
||||
{
|
||||
VerifyMarshalCopyEnabled();
|
||||
Marshal.Copy(source, Convert.ToInt32(sourceIndex), pDestination, Convert.ToInt32(length));
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
fixed (int* pSrc = source)
|
||||
{
|
||||
var pDest = (int*)pDestination;
|
||||
for (var index = 0UL; index < length; index++)
|
||||
{
|
||||
pDest[index] = pSrc[sourceIndex + index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static unsafe ulong WriteSingleArrayToUnmanagedMemory(Array sourceArray, ulong sourceIndex, ulong length, IntPtr pDestination)
|
||||
{
|
||||
var sourceLength = (ulong)sourceArray.LongLength;
|
||||
if (sourceIndex >= sourceLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("sourceIndex");
|
||||
}
|
||||
|
||||
var source = (float[])sourceArray;
|
||||
length = Math.Min(length, sourceLength - sourceIndex);
|
||||
|
||||
try
|
||||
{
|
||||
VerifyMarshalCopyEnabled();
|
||||
Marshal.Copy(source, Convert.ToInt32(sourceIndex), pDestination, Convert.ToInt32(length));
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
fixed (float* pSrc = source)
|
||||
{
|
||||
var pDest = (float*)pDestination;
|
||||
for (var index = 0UL; index < length; index++)
|
||||
{
|
||||
pDest[index] = pSrc[sourceIndex + index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static unsafe ulong WriteDoubleArrayToUnmanagedMemory(Array sourceArray, ulong sourceIndex, ulong length, IntPtr pDestination)
|
||||
{
|
||||
var sourceLength = (ulong)sourceArray.LongLength;
|
||||
if (sourceIndex >= sourceLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("sourceIndex");
|
||||
}
|
||||
|
||||
var source = (double[])sourceArray;
|
||||
length = Math.Min(length, sourceLength - sourceIndex);
|
||||
|
||||
try
|
||||
{
|
||||
VerifyMarshalCopyEnabled();
|
||||
Marshal.Copy(source, Convert.ToInt32(sourceIndex), pDestination, Convert.ToInt32(length));
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
fixed (double* pSrc = source)
|
||||
{
|
||||
var pDest = (double*)pDestination;
|
||||
for (var index = 0UL; index < length; index++)
|
||||
{
|
||||
pDest[index] = pSrc[sourceIndex + index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
#region unit test support
|
||||
|
||||
internal static bool DisableMarshalCopy;
|
||||
|
||||
private static void VerifyMarshalCopyEnabled()
|
||||
{
|
||||
if (DisableMarshalCopy)
|
||||
{
|
||||
throw new OverflowException();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,256 @@
|
|||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.ClearScript.Util
|
||||
{
|
||||
internal abstract class VTablePatcher
|
||||
{
|
||||
private static readonly object dataLock = new object();
|
||||
private static readonly HashSet<IntPtr> patchedVTables = new HashSet<IntPtr>();
|
||||
private static IntPtr hHeap;
|
||||
|
||||
public static VTablePatcher GetInstance()
|
||||
{
|
||||
return Environment.Is64BitProcess ? VTablePatcher64.Instance : VTablePatcher32.Instance;
|
||||
}
|
||||
|
||||
public abstract void PatchDispatchEx(IntPtr pDispatchEx);
|
||||
|
||||
private static void ApplyVTablePatches(IntPtr pInterface, params VTablePatch[] patches)
|
||||
{
|
||||
lock (dataLock)
|
||||
{
|
||||
var pVTable = Marshal.ReadIntPtr(pInterface);
|
||||
if (!patchedVTables.Contains(pVTable))
|
||||
{
|
||||
patchedVTables.Add(pVTable);
|
||||
EnsureHeap();
|
||||
|
||||
foreach (var patch in patches)
|
||||
{
|
||||
var pSlot = pVTable + patch.SlotIndex * IntPtr.Size;
|
||||
var pTarget = Marshal.ReadIntPtr(pSlot);
|
||||
|
||||
uint oldProtect;
|
||||
if (NativeMethods.VirtualProtect(pSlot, (UIntPtr)IntPtr.Size, 0x04 /*PAGE_READWRITE*/, out oldProtect))
|
||||
{
|
||||
var thunkSize = patch.ThunkBytes.Length;
|
||||
var pThunk = NativeMethods.HeapAlloc(hHeap, 0, (UIntPtr)thunkSize);
|
||||
for (var index = 0; index < thunkSize; index++)
|
||||
{
|
||||
Marshal.WriteByte(pThunk + index, patch.ThunkBytes[index]);
|
||||
}
|
||||
|
||||
Marshal.WriteIntPtr(pThunk + patch.TargetOffset, pTarget);
|
||||
Marshal.WriteIntPtr(pSlot, pThunk);
|
||||
NativeMethods.VirtualProtect(pSlot, (UIntPtr)IntPtr.Size, oldProtect, out oldProtect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureHeap()
|
||||
{
|
||||
if (hHeap == IntPtr.Zero)
|
||||
{
|
||||
hHeap = NativeMethods.HeapCreate(0x00040005 /*HEAP_CREATE_ENABLE_EXECUTE|HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE*/, UIntPtr.Zero, UIntPtr.Zero);
|
||||
if (hHeap == IntPtr.Zero)
|
||||
{
|
||||
throw new Win32Exception();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Nested type: VTablePatcher32
|
||||
|
||||
private sealed class VTablePatcher32 : VTablePatcher
|
||||
{
|
||||
public static readonly VTablePatcher Instance = new VTablePatcher32();
|
||||
|
||||
private VTablePatcher32()
|
||||
{
|
||||
}
|
||||
|
||||
public override void PatchDispatchEx(IntPtr pDispatchEx)
|
||||
{
|
||||
// JScript in Standards Mode extends the IDispatchEx contract slightly in order to
|
||||
// pass extra data to the host. This confuses the CLR's IDispatchEx implementation.
|
||||
// The vtable patches below sanitize the arguments before passing them through.
|
||||
|
||||
ApplyVTablePatches(
|
||||
pDispatchEx,
|
||||
new VTablePatch
|
||||
{
|
||||
SlotIndex = 7, // IDispatchEx::GetDispID()
|
||||
ThunkBytes = new byte[] { //-------------------------
|
||||
0x55, // push ebp
|
||||
0x8B, 0xEC, // mov ebp,esp
|
||||
0x81, 0x65, 0x10, 0xFF, 0xFF, 0xFF, 0x0F, // and dword ptr [grfdex],0FFFFFFFh
|
||||
0xB8, 0x0D, 0xF0, 0xAD, 0xBA, // mov eax,0BAADF00Dh <- Target
|
||||
0x5D, // pop ebp
|
||||
0xFF, 0xE0 // jmp eax
|
||||
},
|
||||
TargetOffset = 11
|
||||
},
|
||||
new VTablePatch
|
||||
{
|
||||
SlotIndex = 9, // IDispatchEx::DeleteMemberByName()
|
||||
ThunkBytes = new byte[] { // ---------------------------------
|
||||
0x55, // push ebp
|
||||
0x8B, 0xEC, // mov ebp,esp
|
||||
0x8B, 0x45, 0x10, // mov eax,dword ptr [grfdex]
|
||||
0x25, 0xFF, 0xFF, 0xFF, 0x0F, // and eax,0FFFFFFFh
|
||||
0x89, 0x45, 0x10, // mov dword ptr [grfdex],eax
|
||||
0xB8, 0x0D, 0xF0, 0xAD, 0xBA, // mov eax,0BAADF00Dh <- Target
|
||||
0x5D, // pop ebp
|
||||
0xFF, 0xE0 // jmp eax
|
||||
},
|
||||
TargetOffset = 15
|
||||
},
|
||||
new VTablePatch
|
||||
{
|
||||
SlotIndex = 13, // IDispatchEx::GetNextDispID()
|
||||
ThunkBytes = new byte[] { // ----------------------------
|
||||
0x55, // push ebp
|
||||
0x8B, 0xEC, // mov ebp,esp
|
||||
0x81, 0x65, 0x0C, 0xFF, 0xFF, 0xFF, 0x0F, // and dword ptr [grfdex],0FFFFFFFh
|
||||
0xB8, 0x0D, 0xF0, 0xAD, 0xBA, // mov eax,0BAADF00Dh <- Target
|
||||
0x5D, // pop ebp
|
||||
0xFF, 0xE0 // jmp eax
|
||||
},
|
||||
TargetOffset = 11
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: VTablePatcher64
|
||||
|
||||
private sealed class VTablePatcher64 : VTablePatcher
|
||||
{
|
||||
public static readonly VTablePatcher Instance = new VTablePatcher64();
|
||||
|
||||
private VTablePatcher64()
|
||||
{
|
||||
}
|
||||
|
||||
public override void PatchDispatchEx(IntPtr pDispatchEx)
|
||||
{
|
||||
// JScript in Standards Mode extends the IDispatchEx contract slightly in order to
|
||||
// pass extra data to the host. This confuses the CLR's IDispatchEx implementation.
|
||||
// The vtable patches below sanitize the arguments before passing them through.
|
||||
|
||||
ApplyVTablePatches(
|
||||
pDispatchEx,
|
||||
new VTablePatch
|
||||
{
|
||||
SlotIndex = 7, // IDispatchEx::GetDispID()
|
||||
ThunkBytes = new byte[] { //-------------------------
|
||||
0x41, 0x81, 0xE0, 0xFF, 0xFF, 0xFF, 0x0F, // and r8d,0FFFFFFFh
|
||||
0x48, 0xB8, 0x0D, 0xF0, 0xAD, 0xBA, 0x0D, 0xF0, 0xAD, 0xBA, // mov rax,0BAADF00DBAADF00Dh <- Target
|
||||
0x48, 0xFF, 0xE0 // jmp rax
|
||||
},
|
||||
TargetOffset = 9
|
||||
},
|
||||
new VTablePatch {
|
||||
SlotIndex = 9, // IDispatchEx::DeleteMemberByName()
|
||||
ThunkBytes = new byte[] { // ---------------------------------
|
||||
0x41, 0x81, 0xE0, 0xFF, 0xFF, 0xFF, 0x0F, // and r8d,0FFFFFFFh
|
||||
0x48, 0xB8, 0x0D, 0xF0, 0xAD, 0xBA, 0x0D, 0xF0, 0xAD, 0xBA, // mov rax,0BAADF00DBAADF00Dh <- Target
|
||||
0x48, 0xFF, 0xE0 // jmp rax
|
||||
},
|
||||
TargetOffset = 9
|
||||
},
|
||||
new VTablePatch {
|
||||
SlotIndex = 13, // IDispatchEx::GetNextDispID()
|
||||
ThunkBytes = new byte[] { // ----------------------------
|
||||
0x81, 0xE2, 0xFF, 0xFF, 0xFF, 0x0F, // and edx,0FFFFFFFh
|
||||
0x48, 0xB8, 0x0D, 0xF0, 0xAD, 0xBA, 0x0D, 0xF0, 0xAD, 0xBA, // mov rax,0BAADF00DBAADF00Dh <- Target
|
||||
0x48, 0xFF, 0xE0 // jmp rax
|
||||
},
|
||||
TargetOffset = 8
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: VTablePatch
|
||||
|
||||
private class VTablePatch
|
||||
{
|
||||
public int SlotIndex;
|
||||
public byte[] ThunkBytes;
|
||||
public int TargetOffset;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -66,6 +66,7 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
|
|
|
@ -288,6 +288,41 @@ bool HostObjectHelpers::IsDelegate(void* pvObject)
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
V8Value HostObjectHelpers::GetEnumerator(void* pvObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
return V8ContextProxyImpl::ImportValue(V8ProxyHelpers::GetEnumeratorForHostObject(pvObject));
|
||||
}
|
||||
catch (Exception^ gcException)
|
||||
{
|
||||
ThrowHostException(pvObject, gcException);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool HostObjectHelpers::AdvanceEnumerator(void* pvEnumerator, V8Value& value)
|
||||
{
|
||||
try
|
||||
{
|
||||
Object^ gcValue;
|
||||
if (V8ProxyHelpers::AdvanceEnumerator(pvEnumerator, gcValue))
|
||||
{
|
||||
value = V8ContextProxyImpl::ImportValue(gcValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
catch (Exception^ gcException)
|
||||
{
|
||||
ThrowHostException(pvEnumerator, gcException);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void* HostObjectHelpers::CreateV8ObjectCache()
|
||||
{
|
||||
return V8ProxyHelpers::CreateV8ObjectCache();
|
||||
|
|
|
@ -89,6 +89,9 @@ public:
|
|||
static V8Value InvokeMethod(void* pvObject, const StdString& name, const std::vector<V8Value>& args);
|
||||
static bool IsDelegate(void* pvObject);
|
||||
|
||||
static V8Value GetEnumerator(void* pvObject);
|
||||
static bool AdvanceEnumerator(void* pvEnumerator, V8Value& value);
|
||||
|
||||
static void* CreateV8ObjectCache();
|
||||
static void CacheV8Object(void* pvCache, void* pvObject, void* pvV8Object);
|
||||
static void* GetCachedV8Object(void* pvCache, void* pvObject);
|
||||
|
|
|
@ -87,6 +87,7 @@ using namespace System;
|
|||
using namespace System::Globalization;
|
||||
using namespace System::Runtime::InteropServices;
|
||||
using namespace System::Threading;
|
||||
using namespace Microsoft::ClearScript::JavaScript;
|
||||
using namespace Microsoft::ClearScript::Util;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -104,7 +105,7 @@ using namespace Microsoft::ClearScript::Util;
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define ENSURE_INTERNAL_CLASS(NAME) \
|
||||
public ref class NAME##Hook \
|
||||
public ref class NAME##Anchor \
|
||||
{ \
|
||||
private: \
|
||||
static String^ m_gcName = NAME::typeid->Name; \
|
||||
|
|
|
@ -70,11 +70,11 @@ class Timer: public WeakRefTarget<Timer>
|
|||
public:
|
||||
|
||||
Timer(unsigned int delay, bool repeating, std::function<void(Timer*)>&& func):
|
||||
m_spTimer(std::make_shared<Concurrency::timer<int>>(delay, 0, nullptr, repeating)),
|
||||
m_spTimer(new Concurrency::timer<int>(delay, 0, nullptr, repeating)),
|
||||
m_Func(std::move(func))
|
||||
{
|
||||
auto wrTimer = CreateWeakRef();
|
||||
m_spCall = std::make_shared<Concurrency::call<int>>([wrTimer] (int)
|
||||
m_spCall = new Concurrency::call<int>([wrTimer] (int)
|
||||
{
|
||||
Concurrency::create_task([wrTimer]
|
||||
{
|
||||
|
@ -86,7 +86,7 @@ public:
|
|||
});
|
||||
});
|
||||
|
||||
m_spTimer->link_target(m_spCall.get());
|
||||
m_spTimer->link_target(m_spCall);
|
||||
}
|
||||
|
||||
void Start()
|
||||
|
@ -111,7 +111,7 @@ private:
|
|||
m_Func(this);
|
||||
}
|
||||
|
||||
std::shared_ptr<Concurrency::timer<int>> m_spTimer;
|
||||
std::shared_ptr<Concurrency::call<int>> m_spCall;
|
||||
SharedPtr<Concurrency::timer<int>> m_spTimer;
|
||||
SharedPtr<Concurrency::call<int>> m_spCall;
|
||||
std::function<void(Timer*)> m_Func;
|
||||
};
|
||||
|
|
|
@ -115,22 +115,6 @@ static V8ContextImpl* UnwrapContextImplFromData(const v8::FunctionCallbackInfo<T
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template <typename T>
|
||||
static void* UnwrapHostObject(const v8::PropertyCallbackInfo<T>& info)
|
||||
{
|
||||
return ::GetHostObject(info.Holder());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template <typename T>
|
||||
static void* UnwrapHostObject(const v8::FunctionCallbackInfo<T>& info)
|
||||
{
|
||||
return ::GetHostObject(info.Holder());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template <typename T>
|
||||
static T CombineFlags(T flag1, T flag2)
|
||||
{
|
||||
|
@ -195,6 +179,8 @@ V8ContextImpl::V8ContextImpl(V8IsolateImpl* pIsolateImpl, const StdString& name,
|
|||
|
||||
BEGIN_ISOLATE_SCOPE
|
||||
|
||||
auto propertyHandlerFlags = ::CombineFlags(v8::PropertyHandlerFlags::kNonMasking, v8::PropertyHandlerFlags::kOnlyInterceptStrings);
|
||||
|
||||
if (disableGlobalMembers)
|
||||
{
|
||||
m_hContext = CreatePersistent(CreateContext());
|
||||
|
@ -203,7 +189,6 @@ V8ContextImpl::V8ContextImpl(V8IsolateImpl* pIsolateImpl, const StdString& name,
|
|||
{
|
||||
auto hGlobalTemplate = CreateObjectTemplate();
|
||||
hGlobalTemplate->SetInternalFieldCount(1);
|
||||
auto propertyHandlerFlags = ::CombineFlags(v8::PropertyHandlerFlags::kNonMasking, v8::PropertyHandlerFlags::kOnlyInterceptStrings);
|
||||
hGlobalTemplate->SetHandler(v8::NamedPropertyHandlerConfiguration(GetGlobalProperty, SetGlobalProperty, QueryGlobalProperty, DeleteGlobalProperty, GetGlobalPropertyNames, v8::Local<v8::Value>(), propertyHandlerFlags));
|
||||
hGlobalTemplate->SetHandler(v8::IndexedPropertyHandlerConfiguration(GetGlobalProperty, SetGlobalProperty, QueryGlobalProperty, DeleteGlobalProperty, GetGlobalPropertyIndices));
|
||||
|
||||
|
@ -219,30 +204,44 @@ V8ContextImpl::V8ContextImpl(V8IsolateImpl* pIsolateImpl, const StdString& name,
|
|||
|
||||
m_hHostObjectCookieName = CreatePersistent(CreateString(StdString(L"{c2cf47d3-916b-4a3f-be2a-6ff567425808}")));
|
||||
m_hHostExceptionName = CreatePersistent(CreateString(StdString(L"hostException")));
|
||||
m_hEnumeratorPropertyName = CreatePersistent(CreateString(StdString(L"enumerator")));
|
||||
m_hDonePropertyName = CreatePersistent(CreateString(StdString(L"done")));
|
||||
m_hValuePropertyName = CreatePersistent(CreateString(StdString(L"value")));
|
||||
m_hAccessTokenName = CreatePersistent(CreateString(StdString(L"{cdc19e6e-5d80-4627-a605-bb4805f15086}")));
|
||||
|
||||
v8::Local<v8::Function> hGetIteratorFunction;
|
||||
v8::Local<v8::Function> hToFunctionFunction;
|
||||
v8::Local<v8::Function> hNextFunction;
|
||||
BEGIN_CONTEXT_SCOPE
|
||||
hGetIteratorFunction = CreateFunction(GetIteratorForHostObject, Wrap());
|
||||
hToFunctionFunction = CreateFunction(CreateFunctionForHostDelegate, Wrap());
|
||||
hNextFunction = CreateFunction(AdvanceHostObjectIterator, Wrap());
|
||||
m_hTerminationException = CreatePersistent(v8::Exception::Error(CreateString(StdString(L"Script execution was interrupted"))));
|
||||
END_CONTEXT_SCOPE
|
||||
|
||||
m_hHostObjectTemplate = CreatePersistent(CreateFunctionTemplate());
|
||||
m_hHostObjectTemplate->SetClassName(CreateString(StdString(L"HostObject")));
|
||||
m_hHostObjectTemplate->SetCallHandler(HostObjectConstructorCallHandler, Wrap());
|
||||
m_hHostObjectTemplate->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
m_hHostObjectTemplate->InstanceTemplate()->SetNamedPropertyHandler(GetHostObjectProperty, SetHostObjectProperty, QueryHostObjectProperty, DeleteHostObjectProperty, GetHostObjectPropertyNames, Wrap());
|
||||
m_hHostObjectTemplate->InstanceTemplate()->SetIndexedPropertyHandler(GetHostObjectProperty, SetHostObjectProperty, QueryHostObjectProperty, DeleteHostObjectProperty, GetHostObjectPropertyIndices, Wrap());
|
||||
m_hHostObjectTemplate->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(GetHostObjectProperty, SetHostObjectProperty, QueryHostObjectProperty, DeleteHostObjectProperty, GetHostObjectPropertyNames, Wrap(), propertyHandlerFlags));
|
||||
m_hHostObjectTemplate->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(GetHostObjectProperty, SetHostObjectProperty, QueryHostObjectProperty, DeleteHostObjectProperty, GetHostObjectPropertyIndices, Wrap()));
|
||||
m_hHostObjectTemplate->InstanceTemplate()->SetCallAsFunctionHandler(InvokeHostObject, Wrap());
|
||||
|
||||
v8::Local<v8::Function> hToFunction;
|
||||
BEGIN_CONTEXT_SCOPE
|
||||
hToFunction = CreateFunction(CreateFunctionForHostDelegate, Wrap());
|
||||
m_hTerminationException = CreatePersistent(v8::Exception::Error(CreateString(StdString(L"Script execution was interrupted"))));
|
||||
END_CONTEXT_SCOPE
|
||||
m_hHostObjectTemplate->PrototypeTemplate()->Set(GetIteratorSymbol(), hGetIteratorFunction);
|
||||
|
||||
m_hHostDelegateTemplate = CreatePersistent(CreateFunctionTemplate());
|
||||
m_hHostDelegateTemplate->SetClassName(CreateString(StdString(L"HostDelegate")));
|
||||
m_hHostDelegateTemplate->SetCallHandler(HostObjectConstructorCallHandler, Wrap());
|
||||
m_hHostDelegateTemplate->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
m_hHostDelegateTemplate->InstanceTemplate()->SetNamedPropertyHandler(GetHostObjectProperty, SetHostObjectProperty, QueryHostObjectProperty, DeleteHostObjectProperty, GetHostObjectPropertyNames, Wrap());
|
||||
m_hHostDelegateTemplate->InstanceTemplate()->SetIndexedPropertyHandler(GetHostObjectProperty, SetHostObjectProperty, QueryHostObjectProperty, DeleteHostObjectProperty, GetHostObjectPropertyIndices, Wrap());
|
||||
m_hHostDelegateTemplate->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(GetHostObjectProperty, SetHostObjectProperty, QueryHostObjectProperty, DeleteHostObjectProperty, GetHostObjectPropertyNames, Wrap(), propertyHandlerFlags));
|
||||
m_hHostDelegateTemplate->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(GetHostObjectProperty, SetHostObjectProperty, QueryHostObjectProperty, DeleteHostObjectProperty, GetHostObjectPropertyIndices, Wrap()));
|
||||
m_hHostDelegateTemplate->InstanceTemplate()->SetCallAsFunctionHandler(InvokeHostObject, Wrap());
|
||||
m_hHostDelegateTemplate->PrototypeTemplate()->Set(CreateString(StdString(L"toFunction")), hToFunction);
|
||||
m_hHostDelegateTemplate->PrototypeTemplate()->Set(GetIteratorSymbol(), hGetIteratorFunction);
|
||||
m_hHostDelegateTemplate->PrototypeTemplate()->Set(CreateString(StdString(L"toFunction")), hToFunctionFunction);
|
||||
|
||||
m_hHostIteratorTemplate = CreatePersistent(CreateFunctionTemplate());
|
||||
m_hHostIteratorTemplate->SetClassName(CreateString(StdString(L"HostIterator")));
|
||||
m_hHostIteratorTemplate->SetCallHandler(HostObjectConstructorCallHandler, Wrap());
|
||||
m_hHostIteratorTemplate->PrototypeTemplate()->Set(CreateString(StdString(L"next")), hNextFunction);
|
||||
|
||||
m_spIsolateImpl->AddContext(this, enableDebugging, debugPort);
|
||||
m_pvV8ObjectCache = HostObjectHelpers::CreateV8ObjectCache();
|
||||
|
@ -340,7 +339,7 @@ void V8ContextImpl::SetGlobalProperty(const StdString& name, const V8Value& valu
|
|||
hOldValue = m_hContext->Global()->GetRealNamedProperty(hName);
|
||||
}
|
||||
|
||||
m_hContext->Global()->ForceSet(hName, hValue, (v8::PropertyAttribute)(v8::ReadOnly | v8::DontDelete));
|
||||
m_hContext->Global()->ForceSet(hName, hValue, static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete));
|
||||
if (globalMembers && hValue->IsObject())
|
||||
{
|
||||
if (!hOldValue.IsEmpty() && hOldValue->IsObject())
|
||||
|
@ -573,7 +572,7 @@ V8Value V8ContextImpl::InvokeV8Object(void* pvObject, const std::vector<V8Value>
|
|||
BEGIN_CONTEXT_SCOPE
|
||||
BEGIN_EXECUTION_SCOPE
|
||||
|
||||
auto hObject = ::ObjectHandleFromPtr(pvObject);
|
||||
v8::Local<v8::Object> hObject = ::ObjectHandleFromPtr(pvObject);
|
||||
|
||||
std::vector<v8::Local<v8::Value>> importedArgs;
|
||||
ImportValues(args, importedArgs);
|
||||
|
@ -596,7 +595,7 @@ V8Value V8ContextImpl::InvokeV8ObjectMethod(void* pvObject, const StdString& nam
|
|||
BEGIN_CONTEXT_SCOPE
|
||||
BEGIN_EXECUTION_SCOPE
|
||||
|
||||
auto hObject = ::ObjectHandleFromPtr(pvObject);
|
||||
v8::Local<v8::Object> hObject = ::ObjectHandleFromPtr(pvObject);
|
||||
|
||||
auto hName = CreateString(name);
|
||||
if (!hObject->Has(hName))
|
||||
|
@ -624,6 +623,84 @@ V8Value V8ContextImpl::InvokeV8ObjectMethod(void* pvObject, const StdString& nam
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::GetV8ObjectArrayBufferOrViewInfo(void* pvObject, V8Value& arrayBuffer, size_t& offset, size_t& size, size_t& length)
|
||||
{
|
||||
BEGIN_CONTEXT_SCOPE
|
||||
|
||||
v8::Local<v8::Object> hObject = ::ObjectHandleFromPtr(pvObject);
|
||||
|
||||
if (hObject->IsArrayBuffer())
|
||||
{
|
||||
auto hArrayBuffer = v8::Local<v8::ArrayBuffer>::Cast(hObject);
|
||||
arrayBuffer = ExportValue(hObject);
|
||||
offset = 0;
|
||||
size = hArrayBuffer->ByteLength();
|
||||
length = size;
|
||||
return;
|
||||
}
|
||||
|
||||
if (hObject->IsDataView())
|
||||
{
|
||||
auto hDataView = v8::Local<v8::DataView>::Cast(hObject);
|
||||
arrayBuffer = ExportValue(hDataView->Buffer());
|
||||
offset = hDataView->ByteOffset();
|
||||
size = hDataView->ByteLength();
|
||||
length = size;
|
||||
return;
|
||||
}
|
||||
|
||||
if (hObject->IsTypedArray())
|
||||
{
|
||||
auto hTypedArray = v8::Local<v8::TypedArray>::Cast(hObject);
|
||||
arrayBuffer = ExportValue(hTypedArray->Buffer());
|
||||
offset = hTypedArray->ByteOffset();
|
||||
size = hTypedArray->ByteLength();
|
||||
length = hTypedArray->Length();
|
||||
return;
|
||||
}
|
||||
|
||||
throw V8Exception(V8Exception::Type_General, m_Name, StdString(L"Object is not a V8 array buffer or view"));
|
||||
|
||||
END_CONTEXT_SCOPE
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::InvokeWithV8ObjectArrayBufferOrViewData(void* pvObject, V8ObjectHelpers::ArrayBufferOrViewDataCallbackT* pCallback, void* pvArg)
|
||||
{
|
||||
BEGIN_CONTEXT_SCOPE
|
||||
|
||||
v8::Local<v8::Object> hObject = ::ObjectHandleFromPtr(pvObject);
|
||||
|
||||
if (hObject->IsArrayBuffer())
|
||||
{
|
||||
auto hArrayBuffer = v8::Local<v8::ArrayBuffer>::Cast(hObject);
|
||||
(*pCallback)(hArrayBuffer->GetContents().Data(), pvArg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hObject->IsDataView())
|
||||
{
|
||||
auto hDataView = v8::Local<v8::DataView>::Cast(hObject);
|
||||
(*pCallback)(static_cast<std::uint8_t*>(hDataView->Buffer()->GetContents().Data()) + hDataView->ByteOffset(), pvArg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hObject->IsTypedArray())
|
||||
{
|
||||
auto hTypedArray = v8::Local<v8::TypedArray>::Cast(hObject);
|
||||
(*pCallback)(static_cast<std::uint8_t*>(hTypedArray->Buffer()->GetContents().Data()) + hTypedArray->ByteOffset(), pvArg);
|
||||
return;
|
||||
}
|
||||
|
||||
throw V8Exception(V8Exception::Type_General, m_Name, StdString(L"Object is not a V8 array buffer or view"));
|
||||
|
||||
END_CONTEXT_SCOPE
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::ProcessDebugMessages()
|
||||
{
|
||||
BEGIN_CONTEXT_SCOPE
|
||||
|
@ -658,10 +735,14 @@ V8ContextImpl::~V8ContextImpl()
|
|||
Dispose(it->second);
|
||||
}
|
||||
|
||||
Dispose(m_hHostIteratorTemplate);
|
||||
Dispose(m_hHostDelegateTemplate);
|
||||
Dispose(m_hHostObjectTemplate);
|
||||
Dispose(m_hAccessToken);
|
||||
Dispose(m_hAccessTokenName);
|
||||
Dispose(m_hValuePropertyName);
|
||||
Dispose(m_hDonePropertyName);
|
||||
Dispose(m_hEnumeratorPropertyName);
|
||||
Dispose(m_hHostExceptionName);
|
||||
Dispose(m_hHostObjectCookieName);
|
||||
|
||||
|
@ -799,7 +880,7 @@ void V8ContextImpl::GetV8ObjectPropertyIndices(v8::Local<v8::Object> hObject, st
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::GetGlobalProperty(v8::Local<v8::Name> hName, const v8::PropertyCallbackInfo<v8::Value>& info)
|
||||
void V8ContextImpl::GetGlobalProperty(v8::Local<v8::Name> hKey, const v8::PropertyCallbackInfo<v8::Value>& info)
|
||||
{
|
||||
auto pContextImpl = ::UnwrapContextImplFromHolder(info);
|
||||
if (CheckContextImplForGlobalObjectCallback(pContextImpl))
|
||||
|
@ -807,14 +888,14 @@ void V8ContextImpl::GetGlobalProperty(v8::Local<v8::Name> hName, const v8::Prope
|
|||
const auto& stack = pContextImpl->m_GlobalMembersStack;
|
||||
if (stack.size() > 0)
|
||||
{
|
||||
auto hKey = hName->ToString();
|
||||
if (!hKey->Equals(pContextImpl->m_hHostObjectCookieName))
|
||||
auto hName = hKey->ToString();
|
||||
if (!hName->Equals(pContextImpl->m_hHostObjectCookieName))
|
||||
{
|
||||
for (auto it = stack.rbegin(); it != stack.rend(); it++)
|
||||
{
|
||||
if (it->second->HasOwnProperty(hKey))
|
||||
if (it->second->HasOwnProperty(hName))
|
||||
{
|
||||
CALLBACK_RETURN(it->second->Get(hKey));
|
||||
CALLBACK_RETURN(it->second->Get(hName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -824,7 +905,7 @@ void V8ContextImpl::GetGlobalProperty(v8::Local<v8::Name> hName, const v8::Prope
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::SetGlobalProperty(v8::Local<v8::Name> hName, v8::Local<v8::Value> hValue, const v8::PropertyCallbackInfo<v8::Value>& info)
|
||||
void V8ContextImpl::SetGlobalProperty(v8::Local<v8::Name> hKey, v8::Local<v8::Value> hValue, const v8::PropertyCallbackInfo<v8::Value>& info)
|
||||
{
|
||||
auto pContextImpl = ::UnwrapContextImplFromHolder(info);
|
||||
if (CheckContextImplForGlobalObjectCallback(pContextImpl))
|
||||
|
@ -832,14 +913,14 @@ void V8ContextImpl::SetGlobalProperty(v8::Local<v8::Name> hName, v8::Local<v8::V
|
|||
const auto& stack = pContextImpl->m_GlobalMembersStack;
|
||||
if (stack.size() > 0)
|
||||
{
|
||||
auto hKey = hName->ToString();
|
||||
if (!hKey->Equals(pContextImpl->m_hHostObjectCookieName))
|
||||
auto hName = hKey->ToString();
|
||||
if (!hName->Equals(pContextImpl->m_hHostObjectCookieName))
|
||||
{
|
||||
for (auto it = stack.rbegin(); it != stack.rend(); it++)
|
||||
{
|
||||
if (it->second->HasOwnProperty(hKey))
|
||||
if (it->second->HasOwnProperty(hName))
|
||||
{
|
||||
it->second->Set(hKey, hValue);
|
||||
it->second->Set(hName, hValue);
|
||||
CALLBACK_RETURN(hValue);
|
||||
}
|
||||
}
|
||||
|
@ -850,7 +931,7 @@ void V8ContextImpl::SetGlobalProperty(v8::Local<v8::Name> hName, v8::Local<v8::V
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::QueryGlobalProperty(v8::Local<v8::Name> hName, const v8::PropertyCallbackInfo<v8::Integer>& info)
|
||||
void V8ContextImpl::QueryGlobalProperty(v8::Local<v8::Name> hKey, const v8::PropertyCallbackInfo<v8::Integer>& info)
|
||||
{
|
||||
auto pContextImpl = ::UnwrapContextImplFromHolder(info);
|
||||
if (CheckContextImplForGlobalObjectCallback(pContextImpl))
|
||||
|
@ -858,14 +939,14 @@ void V8ContextImpl::QueryGlobalProperty(v8::Local<v8::Name> hName, const v8::Pro
|
|||
const auto& stack = pContextImpl->m_GlobalMembersStack;
|
||||
if (stack.size() > 0)
|
||||
{
|
||||
auto hKey = hName->ToString();
|
||||
if (!hKey->Equals(pContextImpl->m_hHostObjectCookieName))
|
||||
auto hName = hKey->ToString();
|
||||
if (!hName->Equals(pContextImpl->m_hHostObjectCookieName))
|
||||
{
|
||||
for (auto it = stack.rbegin(); it != stack.rend(); it++)
|
||||
{
|
||||
if (it->second->HasOwnProperty(hKey))
|
||||
if (it->second->HasOwnProperty(hName))
|
||||
{
|
||||
CALLBACK_RETURN(it->second->GetPropertyAttributes(hKey));
|
||||
CALLBACK_RETURN(it->second->GetPropertyAttributes(hName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -875,7 +956,7 @@ void V8ContextImpl::QueryGlobalProperty(v8::Local<v8::Name> hName, const v8::Pro
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::DeleteGlobalProperty(v8::Local<v8::Name> hName, const v8::PropertyCallbackInfo<v8::Boolean>& info)
|
||||
void V8ContextImpl::DeleteGlobalProperty(v8::Local<v8::Name> hKey, const v8::PropertyCallbackInfo<v8::Boolean>& info)
|
||||
{
|
||||
auto pContextImpl = ::UnwrapContextImplFromHolder(info);
|
||||
if (CheckContextImplForGlobalObjectCallback(pContextImpl))
|
||||
|
@ -883,10 +964,10 @@ void V8ContextImpl::DeleteGlobalProperty(v8::Local<v8::Name> hName, const v8::Pr
|
|||
const auto& stack = pContextImpl->m_GlobalMembersStack;
|
||||
if (stack.size() > 0)
|
||||
{
|
||||
auto hKey = hName->ToString();
|
||||
auto hName = hKey->ToString();
|
||||
for (auto it = stack.rbegin(); it != stack.rend(); it++)
|
||||
{
|
||||
if (it->second->HasOwnProperty(hKey))
|
||||
if (it->second->HasOwnProperty(hName))
|
||||
{
|
||||
// WORKAROUND: v8::Object::Delete() crashes if a custom property deleter calls
|
||||
// ThrowException(). Interestingly, there is no crash if the same deleter is
|
||||
|
@ -896,7 +977,7 @@ void V8ContextImpl::DeleteGlobalProperty(v8::Local<v8::Name> hName, const v8::Pr
|
|||
{
|
||||
try
|
||||
{
|
||||
CALLBACK_RETURN(HostObjectHelpers::DeleteProperty(::GetHostObject(it->second), StdString(hKey)));
|
||||
CALLBACK_RETURN(HostObjectHelpers::DeleteProperty(::GetHostObject(it->second), StdString(hName)));
|
||||
}
|
||||
catch (const HostException&)
|
||||
{
|
||||
|
@ -904,7 +985,7 @@ void V8ContextImpl::DeleteGlobalProperty(v8::Local<v8::Name> hName, const v8::Pr
|
|||
}
|
||||
}
|
||||
|
||||
CALLBACK_RETURN(it->second->Delete(hKey));
|
||||
CALLBACK_RETURN(it->second->Delete(hName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -961,7 +1042,7 @@ void V8ContextImpl::GetGlobalPropertyNames(const v8::PropertyCallbackInfo<v8::Ar
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::GetGlobalProperty(unsigned __int32 index, const v8::PropertyCallbackInfo<v8::Value>& info)
|
||||
void V8ContextImpl::GetGlobalProperty(std::uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info)
|
||||
{
|
||||
auto pContextImpl = ::UnwrapContextImplFromHolder(info);
|
||||
if (CheckContextImplForGlobalObjectCallback(pContextImpl))
|
||||
|
@ -983,7 +1064,7 @@ void V8ContextImpl::GetGlobalProperty(unsigned __int32 index, const v8::Property
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::SetGlobalProperty(unsigned __int32 index, v8::Local<v8::Value> hValue, const v8::PropertyCallbackInfo<v8::Value>& info)
|
||||
void V8ContextImpl::SetGlobalProperty(std::uint32_t index, v8::Local<v8::Value> hValue, const v8::PropertyCallbackInfo<v8::Value>& info)
|
||||
{
|
||||
auto pContextImpl = ::UnwrapContextImplFromHolder(info);
|
||||
if (CheckContextImplForGlobalObjectCallback(pContextImpl))
|
||||
|
@ -1006,7 +1087,7 @@ void V8ContextImpl::SetGlobalProperty(unsigned __int32 index, v8::Local<v8::Valu
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::QueryGlobalProperty(unsigned __int32 index, const v8::PropertyCallbackInfo<v8::Integer>& info)
|
||||
void V8ContextImpl::QueryGlobalProperty(std::uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info)
|
||||
{
|
||||
auto pContextImpl = ::UnwrapContextImplFromHolder(info);
|
||||
if (CheckContextImplForGlobalObjectCallback(pContextImpl))
|
||||
|
@ -1029,7 +1110,7 @@ void V8ContextImpl::QueryGlobalProperty(unsigned __int32 index, const v8::Proper
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::DeleteGlobalProperty(unsigned __int32 index, const v8::PropertyCallbackInfo<v8::Boolean>& info)
|
||||
void V8ContextImpl::DeleteGlobalProperty(std::uint32_t index, const v8::PropertyCallbackInfo<v8::Boolean>& info)
|
||||
{
|
||||
auto pContextImpl = ::UnwrapContextImplFromHolder(info);
|
||||
if (CheckContextImplForGlobalObjectCallback(pContextImpl))
|
||||
|
@ -1110,12 +1191,70 @@ void V8ContextImpl::HostObjectConstructorCallHandler(const v8::FunctionCallbackI
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::GetIteratorForHostObject(const v8::FunctionCallbackInfo<v8::Value>& info)
|
||||
{
|
||||
auto pContextImpl = ::UnwrapContextImplFromData(info);
|
||||
if (pContextImpl != nullptr)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto hEnumerator = pContextImpl->ImportValue(HostObjectHelpers::GetEnumerator(::GetHostObject(info.Holder())));
|
||||
|
||||
v8::Local<v8::Object> hIterator;
|
||||
BEGIN_PULSE_VALUE_SCOPE(&pContextImpl->m_AllowHostObjectConstructorCall, true)
|
||||
hIterator = pContextImpl->m_hHostIteratorTemplate->InstanceTemplate()->NewInstance();
|
||||
END_PULSE_VALUE_SCOPE
|
||||
|
||||
hIterator->SetHiddenValue(pContextImpl->m_hEnumeratorPropertyName, hEnumerator);
|
||||
CALLBACK_RETURN(hIterator);
|
||||
}
|
||||
catch (const HostException& exception)
|
||||
{
|
||||
pContextImpl->ThrowScriptException(exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::AdvanceHostObjectIterator(const v8::FunctionCallbackInfo<v8::Value>& info)
|
||||
{
|
||||
auto pContextImpl = ::UnwrapContextImplFromData(info);
|
||||
if (pContextImpl != nullptr)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto hEnumerator = info.Holder()->GetHiddenValue(pContextImpl->m_hEnumeratorPropertyName)->ToObject();
|
||||
auto hResult = pContextImpl->CreateObject();
|
||||
|
||||
V8Value value(V8Value::Undefined);
|
||||
if (HostObjectHelpers::AdvanceEnumerator(::GetHostObject(hEnumerator), value))
|
||||
{
|
||||
hResult->Set(pContextImpl->m_hDonePropertyName, pContextImpl->GetFalse());
|
||||
hResult->Set(pContextImpl->m_hValuePropertyName, pContextImpl->ImportValue(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
hResult->Set(pContextImpl->m_hDonePropertyName, pContextImpl->GetTrue());
|
||||
}
|
||||
|
||||
CALLBACK_RETURN(hResult);
|
||||
}
|
||||
catch (const HostException& exception)
|
||||
{
|
||||
pContextImpl->ThrowScriptException(exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::CreateFunctionForHostDelegate(const v8::FunctionCallbackInfo<v8::Value>& info)
|
||||
{
|
||||
auto pContextImpl = ::UnwrapContextImplFromData(info);
|
||||
if (pContextImpl != nullptr)
|
||||
{
|
||||
CALLBACK_RETURN(pContextImpl->CreateFunction(InvokeHostDelegate, info.This()));
|
||||
CALLBACK_RETURN(pContextImpl->CreateFunction(InvokeHostDelegate, info.Holder()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1154,13 +1293,14 @@ void V8ContextImpl::InvokeHostDelegate(const v8::FunctionCallbackInfo<v8::Value>
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::GetHostObjectProperty(v8::Local<v8::String> hName, const v8::PropertyCallbackInfo<v8::Value>& info)
|
||||
void V8ContextImpl::GetHostObjectProperty(v8::Local<v8::Name> hKey, const v8::PropertyCallbackInfo<v8::Value>& info)
|
||||
{
|
||||
auto pContextImpl = ::UnwrapContextImplFromData(info);
|
||||
if (CheckContextImplForHostObjectCallback(pContextImpl))
|
||||
{
|
||||
try
|
||||
{
|
||||
auto hName = hKey->ToString();
|
||||
if (hName->Equals(pContextImpl->m_hHostObjectCookieName))
|
||||
{
|
||||
CALLBACK_RETURN(true);
|
||||
|
@ -1184,11 +1324,11 @@ void V8ContextImpl::GetHostObjectProperty(v8::Local<v8::String> hName, const v8:
|
|||
END_PULSE_VALUE_SCOPE
|
||||
}
|
||||
|
||||
auto hResult = hHolder->GetHiddenValue(hName);
|
||||
auto hResult = hHolder->GetRealNamedProperty(hName);
|
||||
if (hResult.IsEmpty())
|
||||
{
|
||||
bool isCacheable;
|
||||
hResult = pContextImpl->ImportValue(HostObjectHelpers::GetProperty(::UnwrapHostObject(info), StdString(hName), isCacheable));
|
||||
hResult = pContextImpl->ImportValue(HostObjectHelpers::GetProperty(::GetHostObject(info.Holder()), StdString(hName), isCacheable));
|
||||
if (isCacheable)
|
||||
{
|
||||
hHolder->ForceSet(hName, hResult);
|
||||
|
@ -1206,14 +1346,15 @@ void V8ContextImpl::GetHostObjectProperty(v8::Local<v8::String> hName, const v8:
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::SetHostObjectProperty(v8::Local<v8::String> hName, v8::Local<v8::Value> hValue, const v8::PropertyCallbackInfo<v8::Value>& info)
|
||||
void V8ContextImpl::SetHostObjectProperty(v8::Local<v8::Name> hKey, v8::Local<v8::Value> hValue, const v8::PropertyCallbackInfo<v8::Value>& info)
|
||||
{
|
||||
auto pContextImpl = ::UnwrapContextImplFromData(info);
|
||||
if (CheckContextImplForHostObjectCallback(pContextImpl))
|
||||
{
|
||||
try
|
||||
{
|
||||
HostObjectHelpers::SetProperty(::UnwrapHostObject(info), StdString(hName), pContextImpl->ExportValue(hValue));
|
||||
auto hName = hKey->ToString();
|
||||
HostObjectHelpers::SetProperty(::GetHostObject(info.Holder()), StdString(hName), pContextImpl->ExportValue(hValue));
|
||||
CALLBACK_RETURN(hValue);
|
||||
}
|
||||
catch (const HostException& exception)
|
||||
|
@ -1225,20 +1366,21 @@ void V8ContextImpl::SetHostObjectProperty(v8::Local<v8::String> hName, v8::Local
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::QueryHostObjectProperty(v8::Local<v8::String> hName, const v8::PropertyCallbackInfo<v8::Integer>& info)
|
||||
void V8ContextImpl::QueryHostObjectProperty(v8::Local<v8::Name> hKey, const v8::PropertyCallbackInfo<v8::Integer>& info)
|
||||
{
|
||||
auto pContextImpl = ::UnwrapContextImplFromData(info);
|
||||
if (CheckContextImplForHostObjectCallback(pContextImpl))
|
||||
{
|
||||
try
|
||||
{
|
||||
auto hName = hKey->ToString();
|
||||
if (hName->Equals(pContextImpl->m_hHostObjectCookieName))
|
||||
{
|
||||
CALLBACK_RETURN(v8::ReadOnly | v8::DontEnum | v8::DontDelete);
|
||||
}
|
||||
|
||||
std::vector<StdString> names;
|
||||
HostObjectHelpers::GetPropertyNames(::UnwrapHostObject(info), names);
|
||||
HostObjectHelpers::GetPropertyNames(::GetHostObject(info.Holder()), names);
|
||||
|
||||
StdString name(hName);
|
||||
for (auto it = names.begin(); it != names.end(); it++)
|
||||
|
@ -1258,14 +1400,15 @@ void V8ContextImpl::QueryHostObjectProperty(v8::Local<v8::String> hName, const v
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::DeleteHostObjectProperty(v8::Local<v8::String> hName, const v8::PropertyCallbackInfo<v8::Boolean>& info)
|
||||
void V8ContextImpl::DeleteHostObjectProperty(v8::Local<v8::Name> hKey, const v8::PropertyCallbackInfo<v8::Boolean>& info)
|
||||
{
|
||||
auto pContextImpl = ::UnwrapContextImplFromData(info);
|
||||
if (CheckContextImplForHostObjectCallback(pContextImpl))
|
||||
{
|
||||
try
|
||||
{
|
||||
CALLBACK_RETURN(HostObjectHelpers::DeleteProperty(::UnwrapHostObject(info), StdString(hName)));
|
||||
auto hName = hKey->ToString();
|
||||
CALLBACK_RETURN(HostObjectHelpers::DeleteProperty(::GetHostObject(info.Holder()), StdString(hName)));
|
||||
}
|
||||
catch (const HostException& exception)
|
||||
{
|
||||
|
@ -1284,7 +1427,7 @@ void V8ContextImpl::GetHostObjectPropertyNames(const v8::PropertyCallbackInfo<v8
|
|||
try
|
||||
{
|
||||
std::vector<StdString> names;
|
||||
HostObjectHelpers::GetPropertyNames(::UnwrapHostObject(info), names);
|
||||
HostObjectHelpers::GetPropertyNames(::GetHostObject(info.Holder()), names);
|
||||
auto nameCount = static_cast<int>(names.size());
|
||||
|
||||
auto hImportedNames = pContextImpl->CreateArray(nameCount);
|
||||
|
@ -1304,14 +1447,14 @@ void V8ContextImpl::GetHostObjectPropertyNames(const v8::PropertyCallbackInfo<v8
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::GetHostObjectProperty(unsigned __int32 index, const v8::PropertyCallbackInfo<v8::Value>& info)
|
||||
void V8ContextImpl::GetHostObjectProperty(std::uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info)
|
||||
{
|
||||
auto pContextImpl = ::UnwrapContextImplFromData(info);
|
||||
if (CheckContextImplForHostObjectCallback(pContextImpl))
|
||||
{
|
||||
try
|
||||
{
|
||||
CALLBACK_RETURN(pContextImpl->ImportValue(HostObjectHelpers::GetProperty(::UnwrapHostObject(info), index)));
|
||||
CALLBACK_RETURN(pContextImpl->ImportValue(HostObjectHelpers::GetProperty(::GetHostObject(info.Holder()), index)));
|
||||
}
|
||||
catch (const HostException& exception)
|
||||
{
|
||||
|
@ -1322,14 +1465,14 @@ void V8ContextImpl::GetHostObjectProperty(unsigned __int32 index, const v8::Prop
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::SetHostObjectProperty(unsigned __int32 index, v8::Local<v8::Value> hValue, const v8::PropertyCallbackInfo<v8::Value>& info)
|
||||
void V8ContextImpl::SetHostObjectProperty(std::uint32_t index, v8::Local<v8::Value> hValue, const v8::PropertyCallbackInfo<v8::Value>& info)
|
||||
{
|
||||
auto pContextImpl = ::UnwrapContextImplFromData(info);
|
||||
if (CheckContextImplForHostObjectCallback(pContextImpl))
|
||||
{
|
||||
try
|
||||
{
|
||||
HostObjectHelpers::SetProperty(::UnwrapHostObject(info), index, pContextImpl->ExportValue(hValue));
|
||||
HostObjectHelpers::SetProperty(::GetHostObject(info.Holder()), index, pContextImpl->ExportValue(hValue));
|
||||
CALLBACK_RETURN(hValue);
|
||||
}
|
||||
catch (const HostException& exception)
|
||||
|
@ -1341,7 +1484,7 @@ void V8ContextImpl::SetHostObjectProperty(unsigned __int32 index, v8::Local<v8::
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::QueryHostObjectProperty(unsigned __int32 index, const v8::PropertyCallbackInfo<v8::Integer>& info)
|
||||
void V8ContextImpl::QueryHostObjectProperty(std::uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info)
|
||||
{
|
||||
auto pContextImpl = ::UnwrapContextImplFromData(info);
|
||||
if (CheckContextImplForHostObjectCallback(pContextImpl))
|
||||
|
@ -1349,7 +1492,7 @@ void V8ContextImpl::QueryHostObjectProperty(unsigned __int32 index, const v8::Pr
|
|||
try
|
||||
{
|
||||
std::vector<int> indices;
|
||||
HostObjectHelpers::GetPropertyIndices(::UnwrapHostObject(info), indices);
|
||||
HostObjectHelpers::GetPropertyIndices(::GetHostObject(info.Holder()), indices);
|
||||
|
||||
for (auto it = indices.begin(); it < indices.end(); it++)
|
||||
{
|
||||
|
@ -1368,14 +1511,14 @@ void V8ContextImpl::QueryHostObjectProperty(unsigned __int32 index, const v8::Pr
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ContextImpl::DeleteHostObjectProperty(unsigned __int32 index, const v8::PropertyCallbackInfo<v8::Boolean>& info)
|
||||
void V8ContextImpl::DeleteHostObjectProperty(std::uint32_t index, const v8::PropertyCallbackInfo<v8::Boolean>& info)
|
||||
{
|
||||
auto pContextImpl = ::UnwrapContextImplFromData(info);
|
||||
if (CheckContextImplForHostObjectCallback(pContextImpl))
|
||||
{
|
||||
try
|
||||
{
|
||||
CALLBACK_RETURN(HostObjectHelpers::DeleteProperty(::UnwrapHostObject(info), index));
|
||||
CALLBACK_RETURN(HostObjectHelpers::DeleteProperty(::GetHostObject(info.Holder()), index));
|
||||
}
|
||||
catch (const HostException& exception)
|
||||
{
|
||||
|
@ -1394,7 +1537,7 @@ void V8ContextImpl::GetHostObjectPropertyIndices(const v8::PropertyCallbackInfo<
|
|||
try
|
||||
{
|
||||
std::vector<int> indices;
|
||||
HostObjectHelpers::GetPropertyIndices(::UnwrapHostObject(info), indices);
|
||||
HostObjectHelpers::GetPropertyIndices(::GetHostObject(info.Holder()), indices);
|
||||
auto indexCount = static_cast<int>(indices.size());
|
||||
|
||||
auto hImportedIndices = pContextImpl->CreateArray(indexCount);
|
||||
|
@ -1431,7 +1574,7 @@ void V8ContextImpl::InvokeHostObject(const v8::FunctionCallbackInfo<v8::Value>&
|
|||
exportedArgs.push_back(pContextImpl->ExportValue(info[index]));
|
||||
}
|
||||
|
||||
CALLBACK_RETURN(pContextImpl->ImportValue(HostObjectHelpers::Invoke(::UnwrapHostObject(info), exportedArgs, info.IsConstructCall())));
|
||||
CALLBACK_RETURN(pContextImpl->ImportValue(HostObjectHelpers::Invoke(::GetHostObject(info.Holder()), exportedArgs, info.IsConstructCall())));
|
||||
}
|
||||
catch (const HostException& exception)
|
||||
{
|
||||
|
@ -1489,7 +1632,7 @@ v8::Local<v8::Value> V8ContextImpl::ImportValue(const V8Value& value)
|
|||
}
|
||||
|
||||
{
|
||||
__int32 result;
|
||||
std::int32_t result;
|
||||
if (value.AsInt32(result))
|
||||
{
|
||||
return CreateInteger(result);
|
||||
|
@ -1497,7 +1640,7 @@ v8::Local<v8::Value> V8ContextImpl::ImportValue(const V8Value& value)
|
|||
}
|
||||
|
||||
{
|
||||
unsigned __int32 result;
|
||||
std::uint32_t result;
|
||||
if (value.AsUInt32(result))
|
||||
{
|
||||
return CreateInteger(result);
|
||||
|
@ -1553,7 +1696,8 @@ v8::Local<v8::Value> V8ContextImpl::ImportValue(const V8Value& value)
|
|||
|
||||
{
|
||||
V8ObjectHolder* pHolder;
|
||||
if (value.AsV8Object(pHolder))
|
||||
V8Value::Subtype subtype;
|
||||
if (value.AsV8Object(pHolder, subtype))
|
||||
{
|
||||
return CreateLocal(::ObjectHandleFromPtr(pHolder->GetObject()));
|
||||
}
|
||||
|
@ -1614,7 +1758,33 @@ V8Value V8ContextImpl::ExportValue(v8::Local<v8::Value> hValue)
|
|||
return V8Value(::GetHostObjectHolder(hObject)->Clone());
|
||||
}
|
||||
|
||||
return V8Value(new V8ObjectHolderImpl(GetWeakBinding(), ::PtrFromObjectHandle(CreatePersistent(hObject))));
|
||||
auto subtype = V8Value::Subtype::None;
|
||||
if (hObject->IsArrayBuffer())
|
||||
subtype = V8Value::Subtype::ArrayBuffer;
|
||||
else if (hObject->IsArrayBufferView())
|
||||
if (hObject->IsDataView())
|
||||
subtype = V8Value::Subtype::DataView;
|
||||
else if (hObject->IsTypedArray())
|
||||
if (hObject->IsUint8Array())
|
||||
subtype = V8Value::Subtype::Uint8Array;
|
||||
else if (hObject->IsUint8ClampedArray())
|
||||
subtype = V8Value::Subtype::Uint8ClampedArray;
|
||||
else if (hObject->IsInt8Array())
|
||||
subtype = V8Value::Subtype::Int8Array;
|
||||
else if (hObject->IsUint16Array())
|
||||
subtype = V8Value::Subtype::Uint16Array;
|
||||
else if (hObject->IsInt16Array())
|
||||
subtype = V8Value::Subtype::Int16Array;
|
||||
else if (hObject->IsUint32Array())
|
||||
subtype = V8Value::Subtype::Uint32Array;
|
||||
else if (hObject->IsInt32Array())
|
||||
subtype = V8Value::Subtype::Int32Array;
|
||||
else if (hObject->IsFloat32Array())
|
||||
subtype = V8Value::Subtype::Float32Array;
|
||||
else if (hObject->IsFloat64Array())
|
||||
subtype = V8Value::Subtype::Float64Array;
|
||||
|
||||
return V8Value(new V8ObjectHolderImpl(GetWeakBinding(), ::PtrFromObjectHandle(CreatePersistent(hObject))), subtype);
|
||||
}
|
||||
|
||||
return V8Value(V8Value::Undefined);
|
||||
|
|
|
@ -120,6 +120,9 @@ public:
|
|||
V8Value InvokeV8Object(void* pvObject, const std::vector<V8Value>& args, bool asConstructor);
|
||||
V8Value InvokeV8ObjectMethod(void* pvObject, const StdString& name, const std::vector<V8Value>& args);
|
||||
|
||||
void GetV8ObjectArrayBufferOrViewInfo(void* pvObject, V8Value& arrayBuffer, size_t& offset, size_t& size, size_t& length);
|
||||
void InvokeWithV8ObjectArrayBufferOrViewData(void* pvObject, V8ObjectHelpers::ArrayBufferOrViewDataCallbackT* pCallback, void* pvArg);
|
||||
|
||||
void ProcessDebugMessages();
|
||||
|
||||
private:
|
||||
|
@ -168,6 +171,11 @@ private:
|
|||
return m_spIsolateImpl->GetFalse();
|
||||
}
|
||||
|
||||
v8::Local<v8::Symbol> GetIteratorSymbol()
|
||||
{
|
||||
return m_spIsolateImpl->GetIteratorSymbol();
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> CreateObject()
|
||||
{
|
||||
return m_spIsolateImpl->CreateObject();
|
||||
|
@ -178,12 +186,12 @@ private:
|
|||
return m_spIsolateImpl->CreateNumber(value);
|
||||
}
|
||||
|
||||
v8::Local<v8::Integer> CreateInteger(__int32 value)
|
||||
v8::Local<v8::Integer> CreateInteger(std::int32_t value)
|
||||
{
|
||||
return m_spIsolateImpl->CreateInteger(value);
|
||||
}
|
||||
|
||||
v8::Local<v8::Integer> CreateInteger(unsigned __int32 value)
|
||||
v8::Local<v8::Integer> CreateInteger(std::uint32_t value)
|
||||
{
|
||||
return m_spIsolateImpl->CreateInteger(value);
|
||||
}
|
||||
|
@ -285,6 +293,11 @@ private:
|
|||
return m_spIsolateImpl->IsExecutionTerminating();
|
||||
}
|
||||
|
||||
void CancelTerminateExecution()
|
||||
{
|
||||
m_spIsolateImpl->CancelTerminateExecution();
|
||||
}
|
||||
|
||||
int ContextDisposedNotification()
|
||||
{
|
||||
return m_spIsolateImpl->ContextDisposedNotification();
|
||||
|
@ -318,32 +331,34 @@ private:
|
|||
void GetV8ObjectPropertyNames(v8::Local<v8::Object> hObject, std::vector<StdString>& names);
|
||||
void GetV8ObjectPropertyIndices(v8::Local<v8::Object> hObject, std::vector<int>& indices);
|
||||
|
||||
static void GetGlobalProperty(v8::Local<v8::Name> hName, const v8::PropertyCallbackInfo<v8::Value>& info);
|
||||
static void SetGlobalProperty(v8::Local<v8::Name> hName, v8::Local<v8::Value> hValue, const v8::PropertyCallbackInfo<v8::Value>& info);
|
||||
static void QueryGlobalProperty(v8::Local<v8::Name> hName, const v8::PropertyCallbackInfo<v8::Integer>& info);
|
||||
static void DeleteGlobalProperty(v8::Local<v8::Name> hName, const v8::PropertyCallbackInfo<v8::Boolean>& info);
|
||||
static void GetGlobalProperty(v8::Local<v8::Name> hKey, const v8::PropertyCallbackInfo<v8::Value>& info);
|
||||
static void SetGlobalProperty(v8::Local<v8::Name> hKey, v8::Local<v8::Value> hValue, const v8::PropertyCallbackInfo<v8::Value>& info);
|
||||
static void QueryGlobalProperty(v8::Local<v8::Name> hKey, const v8::PropertyCallbackInfo<v8::Integer>& info);
|
||||
static void DeleteGlobalProperty(v8::Local<v8::Name> hKey, const v8::PropertyCallbackInfo<v8::Boolean>& info);
|
||||
static void GetGlobalPropertyNames(const v8::PropertyCallbackInfo<v8::Array>& info);
|
||||
|
||||
static void GetGlobalProperty(unsigned __int32 index, const v8::PropertyCallbackInfo<v8::Value>& info);
|
||||
static void SetGlobalProperty(unsigned __int32 index, v8::Local<v8::Value> hValue, const v8::PropertyCallbackInfo<v8::Value>& info);
|
||||
static void QueryGlobalProperty(unsigned __int32 index, const v8::PropertyCallbackInfo<v8::Integer>& info);
|
||||
static void DeleteGlobalProperty(unsigned __int32 index, const v8::PropertyCallbackInfo<v8::Boolean>& info);
|
||||
static void GetGlobalProperty(std::uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info);
|
||||
static void SetGlobalProperty(std::uint32_t index, v8::Local<v8::Value> hValue, const v8::PropertyCallbackInfo<v8::Value>& info);
|
||||
static void QueryGlobalProperty(std::uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info);
|
||||
static void DeleteGlobalProperty(std::uint32_t index, const v8::PropertyCallbackInfo<v8::Boolean>& info);
|
||||
static void GetGlobalPropertyIndices(const v8::PropertyCallbackInfo<v8::Array>& info);
|
||||
|
||||
static void HostObjectConstructorCallHandler(const v8::FunctionCallbackInfo<v8::Value>& info);
|
||||
static void GetIteratorForHostObject(const v8::FunctionCallbackInfo<v8::Value>& info);
|
||||
static void AdvanceHostObjectIterator(const v8::FunctionCallbackInfo<v8::Value>& info);
|
||||
static void CreateFunctionForHostDelegate(const v8::FunctionCallbackInfo<v8::Value>& info);
|
||||
static void InvokeHostDelegate(const v8::FunctionCallbackInfo<v8::Value>& info);
|
||||
|
||||
static void GetHostObjectProperty(v8::Local<v8::String> hName, const v8::PropertyCallbackInfo<v8::Value>& info);
|
||||
static void SetHostObjectProperty(v8::Local<v8::String> hName, v8::Local<v8::Value> hValue, const v8::PropertyCallbackInfo<v8::Value>& info);
|
||||
static void QueryHostObjectProperty(v8::Local<v8::String> hName, const v8::PropertyCallbackInfo<v8::Integer>& info);
|
||||
static void DeleteHostObjectProperty(v8::Local<v8::String> hName, const v8::PropertyCallbackInfo<v8::Boolean>& info);
|
||||
static void GetHostObjectProperty(v8::Local<v8::Name> hKey, const v8::PropertyCallbackInfo<v8::Value>& info);
|
||||
static void SetHostObjectProperty(v8::Local<v8::Name> hKey, v8::Local<v8::Value> hValue, const v8::PropertyCallbackInfo<v8::Value>& info);
|
||||
static void QueryHostObjectProperty(v8::Local<v8::Name> hKey, const v8::PropertyCallbackInfo<v8::Integer>& info);
|
||||
static void DeleteHostObjectProperty(v8::Local<v8::Name> hKey, const v8::PropertyCallbackInfo<v8::Boolean>& info);
|
||||
static void GetHostObjectPropertyNames(const v8::PropertyCallbackInfo<v8::Array>& info);
|
||||
|
||||
static void GetHostObjectProperty(unsigned __int32 index, const v8::PropertyCallbackInfo<v8::Value>& info);
|
||||
static void SetHostObjectProperty(unsigned __int32 index, v8::Local<v8::Value> hValue, const v8::PropertyCallbackInfo<v8::Value>& info);
|
||||
static void QueryHostObjectProperty(unsigned __int32 index, const v8::PropertyCallbackInfo<v8::Integer>& info);
|
||||
static void DeleteHostObjectProperty(unsigned __int32 index, const v8::PropertyCallbackInfo<v8::Boolean>& info);
|
||||
static void GetHostObjectProperty(std::uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info);
|
||||
static void SetHostObjectProperty(std::uint32_t index, v8::Local<v8::Value> hValue, const v8::PropertyCallbackInfo<v8::Value>& info);
|
||||
static void QueryHostObjectProperty(std::uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info);
|
||||
static void DeleteHostObjectProperty(std::uint32_t index, const v8::PropertyCallbackInfo<v8::Boolean>& info);
|
||||
static void GetHostObjectPropertyIndices(const v8::PropertyCallbackInfo<v8::Array>& info);
|
||||
|
||||
static void InvokeHostObject(const v8::FunctionCallbackInfo<v8::Value>& info);
|
||||
|
@ -364,10 +379,14 @@ private:
|
|||
std::vector<std::pair<StdString, Persistent<v8::Object>>> m_GlobalMembersStack;
|
||||
Persistent<v8::String> m_hHostObjectCookieName;
|
||||
Persistent<v8::String> m_hHostExceptionName;
|
||||
Persistent<v8::String> m_hEnumeratorPropertyName;
|
||||
Persistent<v8::String> m_hDonePropertyName;
|
||||
Persistent<v8::String> m_hValuePropertyName;
|
||||
Persistent<v8::String> m_hAccessTokenName;
|
||||
Persistent<v8::Object> m_hAccessToken;
|
||||
Persistent<v8::FunctionTemplate> m_hHostObjectTemplate;
|
||||
Persistent<v8::FunctionTemplate> m_hHostDelegateTemplate;
|
||||
Persistent<v8::FunctionTemplate> m_hHostIteratorTemplate;
|
||||
Persistent<v8::Value> m_hTerminationException;
|
||||
SharedPtr<V8WeakContextBinding> m_spWeakBinding;
|
||||
void* m_pvV8ObjectCache;
|
||||
|
|
|
@ -69,9 +69,9 @@ namespace V8 {
|
|||
// local helper functions
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
static void InvokeAction(void* pvActionRef)
|
||||
static void LockCallback(void* pvArg)
|
||||
{
|
||||
(*static_cast<Action^*>(pvActionRef))();
|
||||
(*static_cast<Action^*>(pvArg))();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -140,7 +140,7 @@ namespace V8 {
|
|||
{
|
||||
try
|
||||
{
|
||||
GetContext()->CallWithLock(InvokeAction, &gcAction);
|
||||
GetContext()->CallWithLock(LockCallback, &gcAction);
|
||||
}
|
||||
catch (const V8Exception& exception)
|
||||
{
|
||||
|
@ -433,7 +433,7 @@ namespace V8 {
|
|||
auto gcValue = dynamic_cast<V8ObjectImpl^>(gcObject);
|
||||
if (gcValue != nullptr)
|
||||
{
|
||||
return V8Value(gcValue->GetHolder()->Clone());
|
||||
return V8Value(gcValue->GetHolder()->Clone(), gcValue->GetSubtype());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -476,7 +476,7 @@ namespace V8 {
|
|||
}
|
||||
|
||||
{
|
||||
__int32 result;
|
||||
std::int32_t result;
|
||||
if (value.AsInt32(result))
|
||||
{
|
||||
return result;
|
||||
|
@ -484,7 +484,7 @@ namespace V8 {
|
|||
}
|
||||
|
||||
{
|
||||
unsigned __int32 result;
|
||||
std::uint32_t result;
|
||||
if (value.AsUInt32(result))
|
||||
{
|
||||
return result;
|
||||
|
@ -501,9 +501,10 @@ namespace V8 {
|
|||
|
||||
{
|
||||
V8ObjectHolder* pHolder;
|
||||
if (value.AsV8Object(pHolder))
|
||||
V8Value::Subtype subtype;
|
||||
if (value.AsV8Object(pHolder, subtype))
|
||||
{
|
||||
return gcnew V8ObjectImpl(pHolder->Clone());
|
||||
return gcnew V8ObjectImpl(pHolder->Clone(), subtype);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,9 @@ public:
|
|||
|
||||
virtual void CallOnBackgroundThread(v8::Task* pTask, ExpectedRuntime runtime) override;
|
||||
virtual void CallOnForegroundThread(v8::Isolate* pIsolate, v8::Task* pTask) override;
|
||||
virtual void CallDelayedOnForegroundThread(v8::Isolate* pIsolate, v8::Task* pTask, double delayInSeconds) override;
|
||||
virtual void CallIdleOnForegroundThread(v8::Isolate* pIsolate, v8::IdleTask* pTask) override;
|
||||
virtual bool IdleTasksEnabled(v8::Isolate* pIsolate) override;
|
||||
virtual double MonotonicallyIncreasingTime() override;
|
||||
|
||||
private:
|
||||
|
@ -98,13 +101,30 @@ void V8Platform::EnsureInstalled()
|
|||
|
||||
void V8Platform::CallOnBackgroundThread(v8::Task* pTask, ExpectedRuntime /*runtime*/)
|
||||
{
|
||||
std::shared_ptr<v8::Task> spTask(pTask);
|
||||
Concurrency::create_task([spTask] { spTask->Run(); });
|
||||
SharedPtr<v8::Task> spTask(pTask);
|
||||
Concurrency::create_task([spTask]
|
||||
{
|
||||
spTask->Run();
|
||||
});
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8Platform::CallOnForegroundThread(v8::Isolate* /*pIsolate*/, v8::Task* /*pTask*/)
|
||||
void V8Platform::CallOnForegroundThread(v8::Isolate* pIsolate, v8::Task* pTask)
|
||||
{
|
||||
static_cast<V8IsolateImpl*>(pIsolate->GetData(0))->RunTaskWithLock(pTask);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8Platform::CallDelayedOnForegroundThread(v8::Isolate* pIsolate, v8::Task* pTask, double delayInSeconds)
|
||||
{
|
||||
static_cast<V8IsolateImpl*>(pIsolate->GetData(0))->RunDelayedTaskWithLock(pTask, delayInSeconds);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8Platform::CallIdleOnForegroundThread(v8::Isolate* /*pIsolate*/, v8::IdleTask* /*pTask*/)
|
||||
{
|
||||
// unexpected call to unsupported method
|
||||
std::terminate();
|
||||
|
@ -112,6 +132,13 @@ void V8Platform::CallOnForegroundThread(v8::Isolate* /*pIsolate*/, v8::Task* /*p
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool V8Platform::IdleTasksEnabled(v8::Isolate* /*pIsolate*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
double V8Platform::MonotonicallyIncreasingTime()
|
||||
{
|
||||
return HighResolutionClock::GetRelativeSeconds();
|
||||
|
@ -136,7 +163,7 @@ class V8ArrayBufferAllocator: public v8::ArrayBuffer::Allocator
|
|||
{
|
||||
public:
|
||||
|
||||
static void EnsureInstalled();
|
||||
static V8ArrayBufferAllocator& GetInstance();
|
||||
|
||||
virtual void* Allocate(size_t size) override;
|
||||
virtual void* AllocateUninitialized(size_t size) override;
|
||||
|
@ -152,12 +179,9 @@ private:
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ArrayBufferAllocator::EnsureInstalled()
|
||||
V8ArrayBufferAllocator& V8ArrayBufferAllocator::GetInstance()
|
||||
{
|
||||
std::call_once(ms_InstallationFlag, []
|
||||
{
|
||||
v8::V8::SetArrayBufferAllocator(&ms_Instance);
|
||||
});
|
||||
return ms_Instance;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -241,9 +265,9 @@ V8IsolateImpl::V8IsolateImpl(const StdString& name, const V8IsolateConstraints*
|
|||
m_IsExecutionTerminating(false)
|
||||
{
|
||||
V8Platform::EnsureInstalled();
|
||||
V8ArrayBufferAllocator::EnsureInstalled();
|
||||
|
||||
v8::Isolate::CreateParams params;
|
||||
params.array_buffer_allocator = &V8ArrayBufferAllocator::GetInstance();
|
||||
if (pConstraints != nullptr)
|
||||
{
|
||||
params.constraints.set_max_semi_space_size(pConstraints->GetMaxNewSpaceSize());
|
||||
|
@ -318,19 +342,18 @@ void V8IsolateImpl::EnableDebugging(int debugPort)
|
|||
}
|
||||
|
||||
auto wrIsolate = CreateWeakRef();
|
||||
m_pvDebugAgent = HostObjectHelpers::CreateDebugAgent(m_Name, version, debugPort, [wrIsolate] (HostObjectHelpers::DebugDirective directive, const StdString* pCommand)
|
||||
m_pvDebugAgent = HostObjectHelpers::CreateDebugAgent(m_Name, version, debugPort, [this, wrIsolate] (HostObjectHelpers::DebugDirective directive, const StdString* pCommand)
|
||||
{
|
||||
auto spIsolate = wrIsolate.GetTarget();
|
||||
if (!spIsolate.IsEmpty())
|
||||
{
|
||||
auto pIsolateImpl = static_cast<V8IsolateImpl*>(spIsolate.GetRawPtr());
|
||||
if ((directive == HostObjectHelpers::DebugDirective::SendDebugCommand) && pCommand)
|
||||
{
|
||||
pIsolateImpl->SendDebugCommand(*pCommand);
|
||||
SendDebugCommand(*pCommand);
|
||||
}
|
||||
else if (directive == HostObjectHelpers::DebugDirective::DispatchDebugMessages)
|
||||
{
|
||||
pIsolateImpl->DispatchDebugMessages();
|
||||
DispatchDebugMessages();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -494,6 +517,54 @@ void V8IsolateImpl::ReleaseV8Script(void* pvScript)
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8IsolateImpl::RunTaskWithLock(v8::Task* pTask)
|
||||
{
|
||||
SharedPtr<v8::Task> spTask(pTask);
|
||||
auto wrIsolate = CreateWeakRef();
|
||||
Concurrency::create_task([this, wrIsolate, spTask]
|
||||
{
|
||||
auto spIsolate = wrIsolate.GetTarget();
|
||||
if (!spIsolate.IsEmpty())
|
||||
{
|
||||
CallWithLockNoWait([spTask] (V8IsolateImpl* /*pIsolateImpl*/)
|
||||
{
|
||||
spTask->Run();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8IsolateImpl::RunDelayedTaskWithLock(v8::Task* pTask, double delayInSeconds)
|
||||
{
|
||||
SharedPtr<v8::Task> spTask(pTask);
|
||||
auto wrIsolate = CreateWeakRef();
|
||||
SharedPtr<Timer> spTimer(new Timer(static_cast<unsigned int>(delayInSeconds * 1000), false, [this, wrIsolate, spTask] (Timer* pTimer)
|
||||
{
|
||||
auto spIsolate = wrIsolate.GetTarget();
|
||||
if (!spIsolate.IsEmpty())
|
||||
{
|
||||
CallWithLockNoWait([spTask] (V8IsolateImpl* /*pIsolateImpl*/)
|
||||
{
|
||||
spTask->Run();
|
||||
});
|
||||
|
||||
BEGIN_MUTEX_SCOPE(m_DataMutex)
|
||||
m_TaskTimers.erase(std::remove(m_TaskTimers.begin(), m_TaskTimers.end(), pTimer), m_TaskTimers.end());
|
||||
END_MUTEX_SCOPE
|
||||
}
|
||||
}));
|
||||
|
||||
BEGIN_MUTEX_SCOPE(m_DataMutex)
|
||||
m_TaskTimers.push_back(spTimer);
|
||||
END_MUTEX_SCOPE
|
||||
|
||||
spTimer->Start();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8IsolateImpl::CallWithLockNoWait(std::function<void(V8IsolateImpl*)>&& callback)
|
||||
{
|
||||
if (m_Mutex.TryLock())
|
||||
|
@ -545,7 +616,7 @@ void V8IsolateImpl::CallWithLockAsync(std::function<void(V8IsolateImpl*)>&& call
|
|||
{
|
||||
size_t queueLength;
|
||||
|
||||
BEGIN_MUTEX_SCOPE(m_CallWithLockQueueMutex)
|
||||
BEGIN_MUTEX_SCOPE(m_DataMutex)
|
||||
m_CallWithLockQueue.push(std::move(callback));
|
||||
queueLength = m_CallWithLockQueue.size();
|
||||
END_MUTEX_SCOPE
|
||||
|
@ -570,7 +641,7 @@ void V8IsolateImpl::ProcessCallWithLockQueue()
|
|||
{
|
||||
std::queue<std::function<void(V8IsolateImpl*)>> callWithLockQueue;
|
||||
|
||||
BEGIN_MUTEX_SCOPE(m_CallWithLockQueueMutex)
|
||||
BEGIN_MUTEX_SCOPE(m_DataMutex)
|
||||
std::swap(callWithLockQueue, m_CallWithLockQueue);
|
||||
END_MUTEX_SCOPE
|
||||
|
||||
|
@ -585,7 +656,7 @@ void V8IsolateImpl::ProcessCallWithLockQueue()
|
|||
|
||||
void V8IsolateImpl::SendDebugCommand(const StdString& command)
|
||||
{
|
||||
v8::Debug::SendCommand(m_pIsolate, command.ToCString(), command.GetLength());
|
||||
v8::Debug::SendCommand(m_pIsolate, reinterpret_cast<const uint16_t*>(command.ToCString()), command.GetLength());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -686,7 +757,7 @@ void V8IsolateImpl::EnterExecutionScope(size_t* pStackMarker)
|
|||
}
|
||||
|
||||
// set and record stack address limit
|
||||
m_pIsolate->SetStackLimit(reinterpret_cast<uintptr_t>(pStackLimit));
|
||||
m_pIsolate->SetStackLimit(reinterpret_cast<std::uintptr_t>(pStackLimit));
|
||||
m_pStackLimit = pStackLimit;
|
||||
|
||||
// enter outermost stack usage monitoring scope
|
||||
|
@ -716,6 +787,9 @@ void V8IsolateImpl::ExitExecutionScope()
|
|||
{
|
||||
_ASSERTE(IsCurrent() && IsLocked());
|
||||
|
||||
// cancel termination to allow remaining script frames to execute
|
||||
CancelTerminateExecution();
|
||||
|
||||
// is stack usage monitoring in progress?
|
||||
if (m_StackWatchLevel > 0)
|
||||
{
|
||||
|
@ -726,7 +800,7 @@ void V8IsolateImpl::ExitExecutionScope()
|
|||
if (m_pStackLimit != nullptr)
|
||||
{
|
||||
// V8 has no API for removing a stack address limit
|
||||
m_pIsolate->SetStackLimit(reinterpret_cast<uintptr_t>(s_pMinStackLimit));
|
||||
m_pIsolate->SetStackLimit(reinterpret_cast<std::uintptr_t>(s_pMinStackLimit));
|
||||
m_pStackLimit = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -752,7 +826,7 @@ void V8IsolateImpl::SetUpHeapWatchTimer(size_t maxHeapSize)
|
|||
|
||||
// create heap watch timer
|
||||
auto wrIsolate = CreateWeakRef();
|
||||
m_spHeapWatchTimer = new Timer(static_cast<unsigned int>(std::max(GetHeapSizeSampleInterval(), 250.0)), false, [wrIsolate, maxHeapSize] (Timer* pTimer)
|
||||
m_spHeapWatchTimer = new Timer(static_cast<unsigned int>(std::max(GetHeapSizeSampleInterval(), 250.0)), false, [this, wrIsolate, maxHeapSize] (Timer* pTimer)
|
||||
{
|
||||
// heap watch callback; is the isolate still alive?
|
||||
auto spIsolate = wrIsolate.GetTarget();
|
||||
|
@ -760,7 +834,7 @@ void V8IsolateImpl::SetUpHeapWatchTimer(size_t maxHeapSize)
|
|||
{
|
||||
// yes; request callback on execution thread
|
||||
auto wrTimer = pTimer->CreateWeakRef();
|
||||
static_cast<V8IsolateImpl*>(spIsolate.GetRawPtr())->CallWithLockAsync([wrTimer, maxHeapSize] (V8IsolateImpl* pIsolateImpl)
|
||||
CallWithLockAsync([wrTimer, maxHeapSize] (V8IsolateImpl* pIsolateImpl)
|
||||
{
|
||||
// execution thread callback; is the timer still alive?
|
||||
auto spTimer = wrTimer.GetTarget();
|
||||
|
|
|
@ -178,6 +178,11 @@ public:
|
|||
return v8::False(m_pIsolate);
|
||||
}
|
||||
|
||||
v8::Local<v8::Symbol> GetIteratorSymbol()
|
||||
{
|
||||
return v8::Symbol::GetIterator(m_pIsolate);
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> CreateObject()
|
||||
{
|
||||
return v8::Object::New(m_pIsolate);
|
||||
|
@ -188,12 +193,12 @@ public:
|
|||
return v8::Number::New(m_pIsolate, value);
|
||||
}
|
||||
|
||||
v8::Local<v8::Integer> CreateInteger(__int32 value)
|
||||
v8::Local<v8::Integer> CreateInteger(std::int32_t value)
|
||||
{
|
||||
return v8::Int32::New(m_pIsolate, value);
|
||||
}
|
||||
|
||||
v8::Local<v8::Integer> CreateInteger(unsigned __int32 value)
|
||||
v8::Local<v8::Integer> CreateInteger(std::uint32_t value)
|
||||
{
|
||||
return v8::Uint32::NewFromUnsigned(m_pIsolate, value);
|
||||
}
|
||||
|
@ -296,6 +301,12 @@ public:
|
|||
return m_pIsolate->IsExecutionTerminating() || m_IsExecutionTerminating;
|
||||
}
|
||||
|
||||
void CancelTerminateExecution()
|
||||
{
|
||||
m_pIsolate->CancelTerminateExecution();
|
||||
m_IsExecutionTerminating = false;
|
||||
}
|
||||
|
||||
int ContextDisposedNotification()
|
||||
{
|
||||
return m_pIsolate->ContextDisposedNotification();
|
||||
|
@ -355,6 +366,9 @@ public:
|
|||
void* AddRefV8Script(void* pvScript);
|
||||
void ReleaseV8Script(void* pvScript);
|
||||
|
||||
void RunTaskWithLock(v8::Task* pTask);
|
||||
void RunDelayedTaskWithLock(v8::Task* pTask, double delayInSeconds);
|
||||
|
||||
void CallWithLockNoWait(std::function<void(V8IsolateImpl*)>&& callback);
|
||||
void DECLSPEC_NORETURN ThrowOutOfMemoryException();
|
||||
|
||||
|
@ -382,8 +396,9 @@ private:
|
|||
v8::Isolate* m_pIsolate;
|
||||
RecursiveMutex m_Mutex;
|
||||
std::list<V8ContextImpl*> m_ContextPtrs;
|
||||
SimpleMutex m_CallWithLockQueueMutex;
|
||||
SimpleMutex m_DataMutex;
|
||||
std::queue<std::function<void(V8IsolateImpl*)>> m_CallWithLockQueue;
|
||||
std::vector<SharedPtr<Timer>> m_TaskTimers;
|
||||
bool m_DebuggingEnabled;
|
||||
int m_DebugPort;
|
||||
void* m_pvDebugAgent;
|
||||
|
|
|
@ -141,3 +141,17 @@ V8Value V8ObjectHelpers::InvokeMethod(V8ObjectHolder* pHolder, const StdString&
|
|||
{
|
||||
return GetHolderImpl(pHolder)->InvokeMethod(name, args);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ObjectHelpers::GetArrayBufferOrViewInfo(V8ObjectHolder* pHolder, V8Value& arrayBuffer, size_t& offset, size_t& size, size_t& length)
|
||||
{
|
||||
return GetHolderImpl(pHolder)->GetArrayBufferOrViewInfo(arrayBuffer, offset, size, length);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ObjectHelpers::InvokeWithArrayBufferOrViewData(V8ObjectHolder* pHolder, ArrayBufferOrViewDataCallbackT* pCallback, void* pvArg)
|
||||
{
|
||||
return GetHolderImpl(pHolder)->InvokeWithArrayBufferOrViewData(pCallback, pvArg);
|
||||
}
|
||||
|
|
|
@ -83,4 +83,8 @@ public:
|
|||
|
||||
static V8Value Invoke(V8ObjectHolder* pHolder, const std::vector<V8Value>& args, bool asConstructor);
|
||||
static V8Value InvokeMethod(V8ObjectHolder* pHolder, const StdString& name, const std::vector<V8Value>& args);
|
||||
|
||||
typedef void ArrayBufferOrViewDataCallbackT(void* pvData, void* pvArg);
|
||||
static void GetArrayBufferOrViewInfo(V8ObjectHolder* pHolder, V8Value& arrayBuffer, size_t& offset, size_t& size, size_t& length);
|
||||
static void InvokeWithArrayBufferOrViewData(V8ObjectHolder* pHolder, ArrayBufferOrViewDataCallbackT* pCallback, void* pvArg);
|
||||
};
|
||||
|
|
|
@ -157,6 +157,20 @@ V8Value V8ObjectHolderImpl::InvokeMethod(const StdString& name, const std::vecto
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ObjectHolderImpl::GetArrayBufferOrViewInfo(V8Value& arrayBuffer, size_t& offset, size_t& size, size_t& length) const
|
||||
{
|
||||
m_spBinding->GetContextImpl()->GetV8ObjectArrayBufferOrViewInfo(m_pvObject, arrayBuffer, offset, size, length);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void V8ObjectHolderImpl::InvokeWithArrayBufferOrViewData(V8ObjectHelpers::ArrayBufferOrViewDataCallbackT* pCallback, void* pvArg) const
|
||||
{
|
||||
m_spBinding->GetContextImpl()->InvokeWithV8ObjectArrayBufferOrViewData(m_pvObject, pCallback, pvArg);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
V8ObjectHolderImpl::~V8ObjectHolderImpl()
|
||||
{
|
||||
SharedPtr<V8IsolateImpl> spIsolateImpl;
|
||||
|
|
|
@ -89,6 +89,9 @@ public:
|
|||
V8Value Invoke(const std::vector<V8Value>& args, bool asConstructor) const;
|
||||
V8Value InvokeMethod(const StdString& name, const std::vector<V8Value>& args) const;
|
||||
|
||||
void GetArrayBufferOrViewInfo(V8Value& arrayBuffer, size_t& offset, size_t& size, size_t& length) const;
|
||||
void InvokeWithArrayBufferOrViewData(V8ObjectHelpers::ArrayBufferOrViewDataCallbackT* pCallback, void* pvArg) const;
|
||||
|
||||
~V8ObjectHolderImpl();
|
||||
|
||||
private:
|
||||
|
|
|
@ -65,13 +65,23 @@ namespace Microsoft {
|
|||
namespace ClearScript {
|
||||
namespace V8 {
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// local helper functions
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
static void ArrayBufferOrViewDataCallback(void* pvData, void* pvArg)
|
||||
{
|
||||
(*static_cast<Action<IntPtr>^*>(pvArg))(IntPtr(pvData));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// V8ObjectImpl implementation
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
V8ObjectImpl::V8ObjectImpl(V8ObjectHolder* pHolder):
|
||||
V8ObjectImpl::V8ObjectImpl(V8ObjectHolder* pHolder, V8Value::Subtype subtype):
|
||||
m_gcLock(gcnew Object),
|
||||
m_pspHolder(new SharedPtr<V8ObjectHolder>(pHolder))
|
||||
m_pspHolder(new SharedPtr<V8ObjectHolder>(pHolder)),
|
||||
m_Subtype(subtype)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -251,6 +261,85 @@ namespace V8 {
|
|||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
bool V8ObjectImpl::IsArrayBufferOrView()
|
||||
{
|
||||
return m_Subtype != V8Value::Subtype::None;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
V8ArrayBufferOrViewKind V8ObjectImpl::GetArrayBufferOrViewKind()
|
||||
{
|
||||
auto kind = V8ArrayBufferOrViewKind::None;
|
||||
|
||||
if (m_Subtype == V8Value::Subtype::ArrayBuffer)
|
||||
kind = V8ArrayBufferOrViewKind::ArrayBuffer;
|
||||
else if (m_Subtype == V8Value::Subtype::DataView)
|
||||
kind = V8ArrayBufferOrViewKind::DataView;
|
||||
else if (m_Subtype == V8Value::Subtype::Uint8Array)
|
||||
kind = V8ArrayBufferOrViewKind::Uint8Array;
|
||||
else if (m_Subtype == V8Value::Subtype::Uint8ClampedArray)
|
||||
kind = V8ArrayBufferOrViewKind::Uint8ClampedArray;
|
||||
else if (m_Subtype == V8Value::Subtype::Int8Array)
|
||||
kind = V8ArrayBufferOrViewKind::Int8Array;
|
||||
else if (m_Subtype == V8Value::Subtype::Uint16Array)
|
||||
kind = V8ArrayBufferOrViewKind::Uint16Array;
|
||||
else if (m_Subtype == V8Value::Subtype::Int16Array)
|
||||
kind = V8ArrayBufferOrViewKind::Int16Array;
|
||||
else if (m_Subtype == V8Value::Subtype::Uint32Array)
|
||||
kind = V8ArrayBufferOrViewKind::Uint32Array;
|
||||
else if (m_Subtype == V8Value::Subtype::Int32Array)
|
||||
kind = V8ArrayBufferOrViewKind::Int32Array;
|
||||
else if (m_Subtype == V8Value::Subtype::Float32Array)
|
||||
kind = V8ArrayBufferOrViewKind::Float32Array;
|
||||
else if (m_Subtype == V8Value::Subtype::Float64Array)
|
||||
kind = V8ArrayBufferOrViewKind::Float64Array;
|
||||
|
||||
return kind;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
V8ArrayBufferOrViewInfo^ V8ObjectImpl::GetArrayBufferOrViewInfo()
|
||||
{
|
||||
try
|
||||
{
|
||||
auto kind = GetArrayBufferOrViewKind();
|
||||
if (kind != V8ArrayBufferOrViewKind::None)
|
||||
{
|
||||
V8Value arrayBuffer(V8Value::Null);
|
||||
size_t offset;
|
||||
size_t size;
|
||||
size_t length;
|
||||
|
||||
V8ObjectHelpers::GetArrayBufferOrViewInfo(GetHolder(), arrayBuffer, offset, size, length);
|
||||
return gcnew V8ArrayBufferOrViewInfo(kind, (IV8Object^)V8ContextProxyImpl::ExportValue(arrayBuffer), offset, size, length);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
catch (const V8Exception& exception)
|
||||
{
|
||||
exception.ThrowScriptEngineException();
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
void V8ObjectImpl::InvokeWithArrayBufferOrViewData(Action<IntPtr>^ gcAction)
|
||||
{
|
||||
try
|
||||
{
|
||||
V8ObjectHelpers::InvokeWithArrayBufferOrViewData(GetHolder(), ArrayBufferOrViewDataCallback, &gcAction);
|
||||
}
|
||||
catch (const V8Exception& exception)
|
||||
{
|
||||
exception.ThrowScriptEngineException();
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
SharedPtr<V8ObjectHolder> V8ObjectImpl::GetHolder()
|
||||
{
|
||||
BEGIN_LOCK_SCOPE(m_gcLock)
|
||||
|
@ -267,6 +356,13 @@ namespace V8 {
|
|||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
V8Value::Subtype V8ObjectImpl::GetSubtype()
|
||||
{
|
||||
return m_Subtype;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
V8ObjectImpl::~V8ObjectImpl()
|
||||
{
|
||||
SharedPtr<V8ObjectHolder> spHolder;
|
||||
|
|
|
@ -73,7 +73,7 @@ namespace V8 {
|
|||
{
|
||||
public:
|
||||
|
||||
V8ObjectImpl(V8ObjectHolder* pHolder);
|
||||
V8ObjectImpl(V8ObjectHolder* pHolder, V8Value::Subtype subtype);
|
||||
|
||||
virtual Object^ GetProperty(String^ gcName);
|
||||
virtual Object^ GetProperty(String^ gcName, [Out] Boolean% isCacheable);
|
||||
|
@ -89,7 +89,13 @@ namespace V8 {
|
|||
virtual Object^ Invoke(array<Object^>^ gcArgs, bool asConstructor);
|
||||
virtual Object^ InvokeMethod(String^ gcName, array<Object^>^ gcArgs);
|
||||
|
||||
virtual bool IsArrayBufferOrView();
|
||||
virtual V8ArrayBufferOrViewKind GetArrayBufferOrViewKind();
|
||||
virtual V8ArrayBufferOrViewInfo^ GetArrayBufferOrViewInfo();
|
||||
virtual void InvokeWithArrayBufferOrViewData(Action<IntPtr>^ gcAction);
|
||||
|
||||
SharedPtr<V8ObjectHolder> GetHolder();
|
||||
V8Value::Subtype GetSubtype();
|
||||
|
||||
~V8ObjectImpl();
|
||||
!V8ObjectImpl();
|
||||
|
@ -100,6 +106,7 @@ namespace V8 {
|
|||
|
||||
Object^ m_gcLock;
|
||||
SharedPtr<V8ObjectHolder>* m_pspHolder;
|
||||
V8Value::Subtype m_Subtype;
|
||||
};
|
||||
|
||||
}}}
|
||||
|
|
|
@ -84,59 +84,85 @@ public:
|
|||
Null
|
||||
};
|
||||
|
||||
enum class Subtype: std::uint16_t
|
||||
{
|
||||
None,
|
||||
ArrayBuffer,
|
||||
DataView,
|
||||
Uint8Array,
|
||||
Uint8ClampedArray,
|
||||
Int8Array,
|
||||
Uint16Array,
|
||||
Int16Array,
|
||||
Uint32Array,
|
||||
Int32Array,
|
||||
Float32Array,
|
||||
Float64Array
|
||||
};
|
||||
|
||||
explicit V8Value(NonexistentInitializer):
|
||||
m_Type(Type_Nonexistent)
|
||||
m_Type(Type::Nonexistent),
|
||||
m_Subtype(Subtype::None)
|
||||
{
|
||||
}
|
||||
|
||||
explicit V8Value(UndefinedInitializer):
|
||||
m_Type(Type_Undefined)
|
||||
m_Type(Type::Undefined),
|
||||
m_Subtype(Subtype::None)
|
||||
{
|
||||
}
|
||||
|
||||
explicit V8Value(NullInitializer):
|
||||
m_Type(Type_Null)
|
||||
m_Type(Type::Null),
|
||||
m_Subtype(Subtype::None)
|
||||
{
|
||||
}
|
||||
|
||||
explicit V8Value(bool value):
|
||||
m_Type(Type_Boolean)
|
||||
m_Type(Type::Boolean),
|
||||
m_Subtype(Subtype::None)
|
||||
{
|
||||
m_Data.BooleanValue = value;
|
||||
}
|
||||
|
||||
explicit V8Value(double value):
|
||||
m_Type(Type_Number)
|
||||
m_Type(Type::Number),
|
||||
m_Subtype(Subtype::None)
|
||||
{
|
||||
m_Data.DoubleValue = value;
|
||||
}
|
||||
|
||||
explicit V8Value(__int32 value):
|
||||
m_Type(Type_Int32)
|
||||
explicit V8Value(std::int32_t value):
|
||||
m_Type(Type::Int32),
|
||||
m_Subtype(Subtype::None)
|
||||
{
|
||||
m_Data.Int32Value = value;
|
||||
}
|
||||
|
||||
explicit V8Value(unsigned __int32 value):
|
||||
m_Type(Type_UInt32)
|
||||
explicit V8Value(std::uint32_t value):
|
||||
m_Type(Type::UInt32),
|
||||
m_Subtype(Subtype::None)
|
||||
{
|
||||
m_Data.UInt32Value = value;
|
||||
}
|
||||
|
||||
explicit V8Value(const StdString* pString):
|
||||
m_Type(Type_String)
|
||||
m_Type(Type::String),
|
||||
m_Subtype(Subtype::None)
|
||||
{
|
||||
m_Data.pString = pString;
|
||||
}
|
||||
|
||||
explicit V8Value(V8ObjectHolder* pV8ObjectHolder):
|
||||
m_Type(Type_V8Object)
|
||||
V8Value(V8ObjectHolder* pV8ObjectHolder, Subtype subtype):
|
||||
m_Type(Type::V8Object),
|
||||
m_Subtype(subtype)
|
||||
{
|
||||
m_Data.pV8ObjectHolder = pV8ObjectHolder;
|
||||
}
|
||||
|
||||
explicit V8Value(HostObjectHolder* pHostObjectHolder):
|
||||
m_Type(Type_HostObject)
|
||||
m_Type(Type::HostObject),
|
||||
m_Subtype(Subtype::None)
|
||||
{
|
||||
m_Data.pHostObjectHolder = pHostObjectHolder;
|
||||
}
|
||||
|
@ -167,22 +193,22 @@ public:
|
|||
|
||||
bool IsNonexistent() const
|
||||
{
|
||||
return m_Type == Type_Nonexistent;
|
||||
return m_Type == Type::Nonexistent;
|
||||
}
|
||||
|
||||
bool IsUndefined() const
|
||||
{
|
||||
return m_Type == Type_Undefined;
|
||||
return m_Type == Type::Undefined;
|
||||
}
|
||||
|
||||
bool IsNull() const
|
||||
{
|
||||
return m_Type == Type_Null;
|
||||
return m_Type == Type::Null;
|
||||
}
|
||||
|
||||
bool AsBoolean(bool& result) const
|
||||
{
|
||||
if (m_Type == Type_Boolean)
|
||||
if (m_Type == Type::Boolean)
|
||||
{
|
||||
result = m_Data.BooleanValue;
|
||||
return true;
|
||||
|
@ -193,7 +219,7 @@ public:
|
|||
|
||||
bool AsNumber(double& result) const
|
||||
{
|
||||
if (m_Type == Type_Number)
|
||||
if (m_Type == Type::Number)
|
||||
{
|
||||
result = m_Data.DoubleValue;
|
||||
return true;
|
||||
|
@ -202,9 +228,9 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
bool AsInt32(__int32& result) const
|
||||
bool AsInt32(std::int32_t& result) const
|
||||
{
|
||||
if (m_Type == Type_Int32)
|
||||
if (m_Type == Type::Int32)
|
||||
{
|
||||
result = m_Data.Int32Value;
|
||||
return true;
|
||||
|
@ -213,9 +239,9 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
bool AsUInt32(unsigned __int32& result) const
|
||||
bool AsUInt32(std::uint32_t& result) const
|
||||
{
|
||||
if (m_Type == Type_UInt32)
|
||||
if (m_Type == Type::UInt32)
|
||||
{
|
||||
result = m_Data.UInt32Value;
|
||||
return true;
|
||||
|
@ -226,7 +252,7 @@ public:
|
|||
|
||||
bool AsString(const StdString*& pString) const
|
||||
{
|
||||
if (m_Type == Type_String)
|
||||
if (m_Type == Type::String)
|
||||
{
|
||||
pString = m_Data.pString;
|
||||
return true;
|
||||
|
@ -235,11 +261,12 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
bool AsV8Object(V8ObjectHolder*& pV8ObjectHolder) const
|
||||
bool AsV8Object(V8ObjectHolder*& pV8ObjectHolder, Subtype& subtype) const
|
||||
{
|
||||
if (m_Type == Type_V8Object)
|
||||
if (m_Type == Type::V8Object)
|
||||
{
|
||||
pV8ObjectHolder = m_Data.pV8ObjectHolder;
|
||||
subtype = m_Subtype;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -248,7 +275,7 @@ public:
|
|||
|
||||
bool AsHostObject(HostObjectHolder*& pHostObjectHolder) const
|
||||
{
|
||||
if (m_Type == Type_HostObject)
|
||||
if (m_Type == Type::HostObject)
|
||||
{
|
||||
pHostObjectHolder = m_Data.pHostObjectHolder;
|
||||
return true;
|
||||
|
@ -264,26 +291,26 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
enum Type
|
||||
enum class Type: std::uint16_t
|
||||
{
|
||||
Type_Nonexistent,
|
||||
Type_Undefined,
|
||||
Type_Null,
|
||||
Type_Boolean,
|
||||
Type_Number,
|
||||
Type_Int32,
|
||||
Type_UInt32,
|
||||
Type_String,
|
||||
Type_V8Object,
|
||||
Type_HostObject
|
||||
Nonexistent,
|
||||
Undefined,
|
||||
Null,
|
||||
Boolean,
|
||||
Number,
|
||||
Int32,
|
||||
UInt32,
|
||||
String,
|
||||
V8Object,
|
||||
HostObject
|
||||
};
|
||||
|
||||
union Data
|
||||
{
|
||||
bool BooleanValue;
|
||||
double DoubleValue;
|
||||
__int32 Int32Value;
|
||||
unsigned __int32 UInt32Value;
|
||||
std::int32_t Int32Value;
|
||||
std::uint32_t UInt32Value;
|
||||
const StdString* pString;
|
||||
V8ObjectHolder* pV8ObjectHolder;
|
||||
HostObjectHolder* pHostObjectHolder;
|
||||
|
@ -292,32 +319,33 @@ private:
|
|||
void Copy(const V8Value& that)
|
||||
{
|
||||
m_Type = that.m_Type;
|
||||
m_Subtype = that.m_Subtype;
|
||||
|
||||
if (m_Type == Type_Boolean)
|
||||
if (m_Type == Type::Boolean)
|
||||
{
|
||||
m_Data.BooleanValue = that.m_Data.BooleanValue;
|
||||
}
|
||||
else if (m_Type == Type_Number)
|
||||
else if (m_Type == Type::Number)
|
||||
{
|
||||
m_Data.DoubleValue = that.m_Data.DoubleValue;
|
||||
}
|
||||
else if (m_Type == Type_Int32)
|
||||
else if (m_Type == Type::Int32)
|
||||
{
|
||||
m_Data.Int32Value = that.m_Data.Int32Value;
|
||||
}
|
||||
else if (m_Type == Type_UInt32)
|
||||
else if (m_Type == Type::UInt32)
|
||||
{
|
||||
m_Data.UInt32Value = that.m_Data.UInt32Value;
|
||||
}
|
||||
else if (m_Type == Type_String)
|
||||
else if (m_Type == Type::String)
|
||||
{
|
||||
m_Data.pString = new StdString(*that.m_Data.pString);
|
||||
}
|
||||
else if (m_Type == Type_V8Object)
|
||||
else if (m_Type == Type::V8Object)
|
||||
{
|
||||
m_Data.pV8ObjectHolder = that.m_Data.pV8ObjectHolder->Clone();
|
||||
}
|
||||
else if (m_Type == Type_HostObject)
|
||||
else if (m_Type == Type::HostObject)
|
||||
{
|
||||
m_Data.pHostObjectHolder = that.m_Data.pHostObjectHolder->Clone();
|
||||
}
|
||||
|
@ -326,26 +354,28 @@ private:
|
|||
void Move(V8Value& that)
|
||||
{
|
||||
m_Type = that.m_Type;
|
||||
m_Subtype = that.m_Subtype;
|
||||
m_Data = that.m_Data;
|
||||
that.m_Type = Type_Undefined;
|
||||
that.m_Type = Type::Undefined;
|
||||
}
|
||||
|
||||
void Dispose()
|
||||
{
|
||||
if (m_Type == Type_String)
|
||||
if (m_Type == Type::String)
|
||||
{
|
||||
delete m_Data.pString;
|
||||
}
|
||||
else if (m_Type == Type_V8Object)
|
||||
else if (m_Type == Type::V8Object)
|
||||
{
|
||||
delete m_Data.pV8ObjectHolder;
|
||||
}
|
||||
else if (m_Type == Type_HostObject)
|
||||
else if (m_Type == Type::HostObject)
|
||||
{
|
||||
delete m_Data.pHostObjectHolder;
|
||||
}
|
||||
}
|
||||
|
||||
Type m_Type;
|
||||
Subtype m_Subtype;
|
||||
Data m_Data;
|
||||
};
|
||||
|
|
|
@ -60,11 +60,28 @@
|
|||
//
|
||||
|
||||
using System;
|
||||
using Microsoft.ClearScript.Util;
|
||||
|
||||
namespace Microsoft.ClearScript.V8
|
||||
{
|
||||
internal interface IV8Object : IDynamic, IDisposable
|
||||
internal interface IV8Object : IDisposable
|
||||
{
|
||||
object GetProperty(string name);
|
||||
object GetProperty(string name, out bool isCacheable);
|
||||
void SetProperty(string name, object value);
|
||||
bool DeleteProperty(string name);
|
||||
string[] GetPropertyNames();
|
||||
|
||||
object GetProperty(int index);
|
||||
void SetProperty(int index, object value);
|
||||
bool DeleteProperty(int index);
|
||||
int[] GetPropertyIndices();
|
||||
|
||||
object Invoke(object[] args, bool asConstructor);
|
||||
object InvokeMethod(string name, object[] args);
|
||||
|
||||
bool IsArrayBufferOrView();
|
||||
V8ArrayBufferOrViewKind GetArrayBufferOrViewKind();
|
||||
V8ArrayBufferOrViewInfo GetArrayBufferOrViewInfo();
|
||||
void InvokeWithArrayBufferOrViewData(Action<IntPtr> action);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
diff --git a/build/standalone.gypi b/build/standalone.gypi
|
||||
index 7c96720..0b046cd 100644
|
||||
index 7250579..86c6334 100644
|
||||
--- a/build/standalone.gypi
|
||||
+++ b/build/standalone.gypi
|
||||
@@ -464,7 +464,7 @@
|
||||
@@ -821,7 +821,7 @@
|
||||
'EnableFunctionLevelLinking': 'true',
|
||||
'RuntimeTypeInfo': 'false',
|
||||
'WarningLevel': '3',
|
||||
|
@ -11,39 +11,11 @@ index 7c96720..0b046cd 100644
|
|||
'DebugInformationFormat': '3',
|
||||
'Detect64BitPortabilityProblems': 'false',
|
||||
'conditions': [
|
||||
diff --git a/src/api.cc b/src/api.cc
|
||||
index 4f06873..546f1f5 100644
|
||||
--- a/src/api.cc
|
||||
+++ b/src/api.cc
|
||||
@@ -5319,10 +5319,6 @@ void v8::V8::SetReturnAddressLocationResolver(
|
||||
|
||||
void v8::V8::SetArrayBufferAllocator(
|
||||
ArrayBuffer::Allocator* allocator) {
|
||||
- if (!Utils::ApiCheck(i::V8::ArrayBufferAllocator() == NULL,
|
||||
- "v8::V8::SetArrayBufferAllocator",
|
||||
- "ArrayBufferAllocator might only be set once"))
|
||||
- return;
|
||||
i::V8::SetArrayBufferAllocator(allocator);
|
||||
}
|
||||
|
||||
diff --git a/src/objects.cc b/src/objects.cc
|
||||
index f0dcaab..4cc1d99 100644
|
||||
--- a/src/objects.cc
|
||||
+++ b/src/objects.cc
|
||||
@@ -6690,7 +6690,7 @@ MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
|
||||
if (is_observed) {
|
||||
if (is_element) {
|
||||
Maybe<bool> maybe = HasOwnElement(object, index);
|
||||
- // Workaround for a GCC 4.4.3 bug which leads to "‘preexists’ may be used
|
||||
+ // Workaround for a GCC 4.4.3 bug which leads to "'preexists' may be used
|
||||
// uninitialized in this function".
|
||||
if (!maybe.IsJust()) {
|
||||
DCHECK(false);
|
||||
diff --git a/src/parser.cc b/src/parser.cc
|
||||
index 3b537d2..17d8c97 100644
|
||||
index 1bd163c..71fbe15 100644
|
||||
--- a/src/parser.cc
|
||||
+++ b/src/parser.cc
|
||||
@@ -2642,7 +2642,7 @@ Statement* Parser::ParseExpressionOrLabelledStatement(
|
||||
@@ -2623,7 +2623,7 @@ Statement* Parser::ParseExpressionOrLabelledStatement(
|
||||
// Identifier ':' Statement
|
||||
//
|
||||
// ExpressionStatement[Yield] :
|
||||
|
@ -53,10 +25,10 @@ index 3b537d2..17d8c97 100644
|
|||
int pos = peek_position();
|
||||
|
||||
diff --git a/src/v8.cc b/src/v8.cc
|
||||
index 49a104f..08fd6f3 100644
|
||||
index 760a9b5..2618312 100644
|
||||
--- a/src/v8.cc
|
||||
+++ b/src/v8.cc
|
||||
@@ -109,7 +109,6 @@ void V8::InitializeOncePerProcess() {
|
||||
@@ -101,7 +101,6 @@ void V8::InitializeOncePerProcess() {
|
||||
|
||||
|
||||
void V8::InitializePlatform(v8::Platform* platform) {
|
||||
|
@ -64,23 +36,11 @@ index 49a104f..08fd6f3 100644
|
|||
CHECK(platform);
|
||||
platform_ = platform;
|
||||
}
|
||||
diff --git a/src/v8.h b/src/v8.h
|
||||
index 211f3c6..7e29fc2 100644
|
||||
--- a/src/v8.h
|
||||
+++ b/src/v8.h
|
||||
@@ -74,7 +74,6 @@ class V8 : public AllStatic {
|
||||
}
|
||||
|
||||
static void SetArrayBufferAllocator(v8::ArrayBuffer::Allocator *allocator) {
|
||||
- CHECK_NULL(array_buffer_allocator_);
|
||||
array_buffer_allocator_ = allocator;
|
||||
}
|
||||
|
||||
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
|
||||
index 70d4dee..7fd3018 100644
|
||||
index bcb5801..efc51ba 100644
|
||||
--- a/tools/gyp/v8.gyp
|
||||
+++ b/tools/gyp/v8.gyp
|
||||
@@ -38,6 +38,7 @@
|
||||
@@ -40,6 +40,7 @@
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'v8',
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
//
|
||||
// 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
|
||||
{
|
||||
internal class V8ArrayBufferOrViewInfo
|
||||
{
|
||||
public V8ArrayBufferOrViewInfo(V8ArrayBufferOrViewKind kind, IV8Object arrayBuffer, ulong offset, ulong size, ulong length)
|
||||
{
|
||||
Kind = kind;
|
||||
ArrayBuffer = arrayBuffer;
|
||||
Offset = offset;
|
||||
Size = size;
|
||||
Length = length;
|
||||
}
|
||||
|
||||
public V8ArrayBufferOrViewKind Kind { get; private set; }
|
||||
|
||||
public IV8Object ArrayBuffer { get; private set; }
|
||||
|
||||
public ulong Offset { get; private set; }
|
||||
|
||||
public ulong Size { get; private set; }
|
||||
|
||||
public ulong Length { get; private set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
//
|
||||
// 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
|
||||
{
|
||||
internal enum V8ArrayBufferOrViewKind
|
||||
{
|
||||
None,
|
||||
ArrayBuffer,
|
||||
DataView,
|
||||
Uint8Array,
|
||||
Uint8ClampedArray,
|
||||
Int8Array,
|
||||
Uint16Array,
|
||||
Int16Array,
|
||||
Uint32Array,
|
||||
Int32Array,
|
||||
Float32Array,
|
||||
Float64Array
|
||||
}
|
||||
}
|
|
@ -65,7 +65,6 @@ using System.ComponentModel;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Microsoft.ClearScript.Util;
|
||||
|
||||
|
@ -170,7 +169,7 @@ namespace Microsoft.ClearScript.V8
|
|||
return hLibrary;
|
||||
}
|
||||
|
||||
var exception = new Win32Exception(Marshal.GetLastWin32Error());
|
||||
var exception = new Win32Exception();
|
||||
messageBuilder.AppendInvariant("\n{0}: {1}", path, MiscHelpers.EnsureNonBlank(exception.Message, "Unknown error"));
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
//
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
@ -116,7 +117,7 @@ namespace Microsoft.ClearScript.V8
|
|||
|
||||
public static object GetHostObjectProperty(object obj, string name)
|
||||
{
|
||||
return ((IDynamic)obj).GetProperty(name);
|
||||
return ((IDynamic)obj).GetProperty(name, MiscHelpers.GetEmptyArray<object>());
|
||||
}
|
||||
|
||||
public static unsafe object GetHostObjectProperty(void* pObject, string name, out bool isCacheable)
|
||||
|
@ -126,7 +127,7 @@ namespace Microsoft.ClearScript.V8
|
|||
|
||||
public static object GetHostObjectProperty(object obj, string name, out bool isCacheable)
|
||||
{
|
||||
return ((IDynamic)obj).GetProperty(name, out isCacheable);
|
||||
return ((IDynamic)obj).GetProperty(name, MiscHelpers.GetEmptyArray<object>(), out isCacheable);
|
||||
}
|
||||
|
||||
public static unsafe void SetHostObjectProperty(void* pObject, string name, object value)
|
||||
|
@ -136,7 +137,7 @@ namespace Microsoft.ClearScript.V8
|
|||
|
||||
public static void SetHostObjectProperty(object obj, string name, object value)
|
||||
{
|
||||
((IDynamic)obj).SetProperty(name, value);
|
||||
((IDynamic)obj).SetProperty(name, new[] { value });
|
||||
}
|
||||
|
||||
public static unsafe bool DeleteHostObjectProperty(void* pObject, string name)
|
||||
|
@ -241,6 +242,34 @@ namespace Microsoft.ClearScript.V8
|
|||
return hostTarget.Flags.HasFlag(HostTargetFlags.AllowInstanceMembers) && typeof(Delegate).IsAssignableFrom(hostTarget.Type);
|
||||
}
|
||||
|
||||
public static unsafe object GetEnumeratorForHostObject(void* pObject)
|
||||
{
|
||||
return GetEnumeratorForHostObject(GetHostObject(pObject));
|
||||
}
|
||||
|
||||
public static object GetEnumeratorForHostObject(object obj)
|
||||
{
|
||||
return ((IDynamic)obj).InvokeMethod(SpecialMemberNames.NewEnum, MiscHelpers.GetEmptyArray<object>());
|
||||
}
|
||||
|
||||
public static unsafe bool AdvanceEnumerator(void* pEnumerator, out object value)
|
||||
{
|
||||
return AdvanceEnumerator(GetHostObject(pEnumerator), out value);
|
||||
}
|
||||
|
||||
public static bool AdvanceEnumerator(object enumerator, out object value)
|
||||
{
|
||||
var wrapper = (IScriptMarshalWrapper)enumerator;
|
||||
if (((IEnumerator)wrapper.Unwrap()).MoveNext())
|
||||
{
|
||||
value = ((IDynamic)enumerator).GetProperty("Current", MiscHelpers.GetEmptyArray<object>());
|
||||
return true;
|
||||
}
|
||||
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region exception marshaling
|
||||
|
|
|
@ -289,8 +289,8 @@ namespace Microsoft.ClearScript.V8
|
|||
return {
|
||||
|
||||
getCommandResult: function (value) {
|
||||
if (value != null) {
|
||||
if (((typeof(value) == 'object') && !value.hasOwnProperty('{c2cf47d3-916b-4a3f-be2a-6ff567425808}')) || (typeof(value) == 'function')) {
|
||||
if ((value != null) && !value.hasOwnProperty('{c2cf47d3-916b-4a3f-be2a-6ff567425808}')) {
|
||||
if ((typeof(value) == 'object') || (typeof(value) == 'function')) {
|
||||
if (typeof(value.toString) == 'function') {
|
||||
return value.toString();
|
||||
}
|
||||
|
@ -719,7 +719,7 @@ namespace Microsoft.ClearScript.V8
|
|||
}
|
||||
|
||||
var hostTarget = obj as HostTarget;
|
||||
if (hostTarget != null)
|
||||
if ((hostTarget != null) && !(hostTarget is IHostVariable))
|
||||
{
|
||||
obj = hostTarget.Target;
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Dynamic;
|
||||
using Microsoft.ClearScript.JavaScript;
|
||||
using Microsoft.ClearScript.Util;
|
||||
|
||||
namespace Microsoft.ClearScript.V8
|
||||
|
@ -91,7 +92,37 @@ namespace Microsoft.ClearScript.V8
|
|||
var target = obj as IV8Object;
|
||||
if (target != null)
|
||||
{
|
||||
return new V8ScriptItem(engine, target);
|
||||
if (!target.IsArrayBufferOrView())
|
||||
{
|
||||
return new V8ScriptItem(engine, target);
|
||||
}
|
||||
|
||||
switch (target.GetArrayBufferOrViewKind())
|
||||
{
|
||||
case V8ArrayBufferOrViewKind.ArrayBuffer:
|
||||
return new V8ArrayBuffer(engine, target);
|
||||
case V8ArrayBufferOrViewKind.DataView:
|
||||
return new V8DataView(engine, target);
|
||||
case V8ArrayBufferOrViewKind.Uint8Array:
|
||||
case V8ArrayBufferOrViewKind.Uint8ClampedArray:
|
||||
return new V8TypedArray<byte>(engine, target);
|
||||
case V8ArrayBufferOrViewKind.Int8Array:
|
||||
return new V8TypedArray<sbyte>(engine, target);
|
||||
case V8ArrayBufferOrViewKind.Uint16Array:
|
||||
return new V8UInt16Array(engine, target);
|
||||
case V8ArrayBufferOrViewKind.Int16Array:
|
||||
return new V8TypedArray<short>(engine, target);
|
||||
case V8ArrayBufferOrViewKind.Uint32Array:
|
||||
return new V8TypedArray<uint>(engine, target);
|
||||
case V8ArrayBufferOrViewKind.Int32Array:
|
||||
return new V8TypedArray<int>(engine, target);
|
||||
case V8ArrayBufferOrViewKind.Float32Array:
|
||||
return new V8TypedArray<float>(engine, target);
|
||||
case V8ArrayBufferOrViewKind.Float64Array:
|
||||
return new V8TypedArray<double>(engine, target);
|
||||
default:
|
||||
return new V8ScriptItem(engine, target);
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
|
@ -209,9 +240,13 @@ namespace Microsoft.ClearScript.V8
|
|||
|
||||
#region IDynamic implementation
|
||||
|
||||
public override object GetProperty(string name)
|
||||
public override object GetProperty(string name, object[] args)
|
||||
{
|
||||
VerifyNotDisposed();
|
||||
if ((args != null) && (args.Length != 0))
|
||||
{
|
||||
throw new InvalidOperationException("Invalid argument or index count");
|
||||
}
|
||||
|
||||
var result = engine.MarshalToHost(engine.ScriptInvoke(() => target.GetProperty(name)), false);
|
||||
|
||||
|
@ -224,10 +259,15 @@ namespace Microsoft.ClearScript.V8
|
|||
return result;
|
||||
}
|
||||
|
||||
public override void SetProperty(string name, object value)
|
||||
public override void SetProperty(string name, object[] args)
|
||||
{
|
||||
VerifyNotDisposed();
|
||||
engine.ScriptInvoke(() => target.SetProperty(name, engine.MarshalToScript(value)));
|
||||
if ((args == null) || (args.Length != 1))
|
||||
{
|
||||
throw new InvalidOperationException("Invalid argument or index count");
|
||||
}
|
||||
|
||||
engine.ScriptInvoke(() => target.SetProperty(name, engine.MarshalToScript(args[0])));
|
||||
}
|
||||
|
||||
public override bool DeleteProperty(string name)
|
||||
|
@ -311,5 +351,391 @@ namespace Microsoft.ClearScript.V8
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: V8ArrayBufferOrView
|
||||
|
||||
private class V8ArrayBufferOrView : V8ScriptItem
|
||||
{
|
||||
private V8ArrayBufferOrViewInfo info;
|
||||
private IArrayBuffer arrayBuffer;
|
||||
|
||||
protected V8ArrayBufferOrView(V8ScriptEngine engine, IV8Object target)
|
||||
: base(engine, target)
|
||||
{
|
||||
}
|
||||
|
||||
protected IArrayBuffer ArrayBuffer
|
||||
{
|
||||
get { return GetArrayBuffer(); }
|
||||
}
|
||||
|
||||
protected ulong Offset
|
||||
{
|
||||
get { return GetInfo().Offset; }
|
||||
}
|
||||
|
||||
protected ulong Size
|
||||
{
|
||||
get { return GetInfo().Size; }
|
||||
}
|
||||
|
||||
protected ulong Length
|
||||
{
|
||||
get { return GetInfo().Length; }
|
||||
}
|
||||
|
||||
protected byte[] GetBytes()
|
||||
{
|
||||
return engine.ScriptInvoke(() =>
|
||||
{
|
||||
var result = new byte[Size];
|
||||
target.InvokeWithArrayBufferOrViewData(pData =>
|
||||
{
|
||||
UnmanagedMemoryHelpers.Copy(pData, Size, result, 0);
|
||||
});
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
protected ulong ReadBytes(ulong offset, ulong count, byte[] destination, ulong destinationIndex)
|
||||
{
|
||||
var size = Size;
|
||||
if (offset >= size)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("offset");
|
||||
}
|
||||
|
||||
count = Math.Min(count, size - offset);
|
||||
return engine.ScriptInvoke(() =>
|
||||
{
|
||||
target.InvokeWithArrayBufferOrViewData(pData =>
|
||||
{
|
||||
count = UnmanagedMemoryHelpers.Copy(GetPtrWithOffset(pData, offset), count, destination, destinationIndex);
|
||||
});
|
||||
|
||||
return count;
|
||||
});
|
||||
}
|
||||
|
||||
protected ulong WriteBytes(byte[] source, ulong sourceIndex, ulong count, ulong offset)
|
||||
{
|
||||
var size = Size;
|
||||
if (offset >= size)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("offset");
|
||||
}
|
||||
|
||||
count = Math.Min(count, size - offset);
|
||||
return engine.ScriptInvoke(() =>
|
||||
{
|
||||
target.InvokeWithArrayBufferOrViewData(pData =>
|
||||
{
|
||||
count = UnmanagedMemoryHelpers.Copy(source, sourceIndex, count, GetPtrWithOffset(pData, offset));
|
||||
});
|
||||
|
||||
return count;
|
||||
});
|
||||
}
|
||||
|
||||
private V8ArrayBufferOrViewInfo GetInfo()
|
||||
{
|
||||
VerifyNotDisposed();
|
||||
|
||||
if (info == null)
|
||||
{
|
||||
engine.ScriptInvoke(() =>
|
||||
{
|
||||
if (info == null)
|
||||
{
|
||||
info = target.GetArrayBufferOrViewInfo();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
private IArrayBuffer GetArrayBuffer()
|
||||
{
|
||||
if (arrayBuffer == null)
|
||||
{
|
||||
arrayBuffer = (IArrayBuffer)engine.MarshalToHost(GetInfo().ArrayBuffer, false);
|
||||
}
|
||||
|
||||
return arrayBuffer;
|
||||
}
|
||||
|
||||
private static IntPtr GetPtrWithOffset(IntPtr pData, ulong offset)
|
||||
{
|
||||
var baseAddr = unchecked((ulong)pData.ToInt64());
|
||||
return new IntPtr(unchecked((long)checked(baseAddr + offset)));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: V8ArrayBuffer
|
||||
|
||||
private class V8ArrayBuffer : V8ArrayBufferOrView, IArrayBuffer
|
||||
{
|
||||
public V8ArrayBuffer(V8ScriptEngine engine, IV8Object target)
|
||||
: base(engine, target)
|
||||
{
|
||||
}
|
||||
|
||||
#region IArrayBuffer implementation
|
||||
|
||||
ulong IArrayBuffer.Size
|
||||
{
|
||||
get { return Size; }
|
||||
}
|
||||
|
||||
byte[] IArrayBuffer.GetBytes()
|
||||
{
|
||||
return GetBytes();
|
||||
}
|
||||
|
||||
ulong IArrayBuffer.ReadBytes(ulong offset, ulong count, byte[] destination, ulong destinationIndex)
|
||||
{
|
||||
return ReadBytes(offset, count, destination, destinationIndex);
|
||||
}
|
||||
|
||||
ulong IArrayBuffer.WriteBytes(byte[] source, ulong sourceIndex, ulong count, ulong offset)
|
||||
{
|
||||
return WriteBytes(source, sourceIndex, count, offset);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: V8ArrayBufferView
|
||||
|
||||
private class V8ArrayBufferView : V8ArrayBufferOrView, IArrayBufferView
|
||||
{
|
||||
protected V8ArrayBufferView(V8ScriptEngine engine, IV8Object target)
|
||||
: base(engine, target)
|
||||
{
|
||||
}
|
||||
|
||||
#region IArrayBufferView implementation
|
||||
|
||||
IArrayBuffer IArrayBufferView.ArrayBuffer
|
||||
{
|
||||
get { return ArrayBuffer; }
|
||||
}
|
||||
|
||||
ulong IArrayBufferView.Offset
|
||||
{
|
||||
get { return Offset; }
|
||||
}
|
||||
|
||||
ulong IArrayBufferView.Size
|
||||
{
|
||||
get { return Size; }
|
||||
}
|
||||
|
||||
byte[] IArrayBufferView.GetBytes()
|
||||
{
|
||||
return GetBytes();
|
||||
}
|
||||
|
||||
ulong IArrayBufferView.ReadBytes(ulong offset, ulong count, byte[] destination, ulong destinationIndex)
|
||||
{
|
||||
return ReadBytes(offset, count, destination, destinationIndex);
|
||||
}
|
||||
|
||||
ulong IArrayBufferView.WriteBytes(byte[] source, ulong sourceIndex, ulong count, ulong offset)
|
||||
{
|
||||
return WriteBytes(source, sourceIndex, count, offset);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: V8DataView
|
||||
|
||||
private class V8DataView : V8ArrayBufferView, IDataView
|
||||
{
|
||||
public V8DataView(V8ScriptEngine engine, IV8Object target)
|
||||
: base(engine, target)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: V8TypedArray
|
||||
|
||||
private class V8TypedArray : V8ArrayBufferView, ITypedArray
|
||||
{
|
||||
protected V8TypedArray(V8ScriptEngine engine, IV8Object target)
|
||||
: base(engine, target)
|
||||
{
|
||||
}
|
||||
|
||||
protected IntPtr GetPtrWithIndex(IntPtr pData, ulong index)
|
||||
{
|
||||
var baseAddr = unchecked((ulong)pData.ToInt64());
|
||||
return new IntPtr(unchecked((long)checked(baseAddr + (index * (Size / Length)))));
|
||||
}
|
||||
|
||||
#region ITypedArray implementation
|
||||
|
||||
ulong ITypedArray.Length
|
||||
{
|
||||
get { return Length; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: V8TypedArray<T>
|
||||
|
||||
private class V8TypedArray<T> : V8TypedArray, ITypedArray<T>
|
||||
{
|
||||
public V8TypedArray(V8ScriptEngine engine, IV8Object target)
|
||||
: base(engine, target)
|
||||
{
|
||||
}
|
||||
|
||||
#region ITypedArray<T> implementation
|
||||
|
||||
T[] ITypedArray<T>.ToArray()
|
||||
{
|
||||
return engine.ScriptInvoke(() =>
|
||||
{
|
||||
var result = new T[Length];
|
||||
target.InvokeWithArrayBufferOrViewData(pData =>
|
||||
{
|
||||
UnmanagedMemoryHelpers.Copy(pData, Length, result, 0);
|
||||
});
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
ulong ITypedArray<T>.Read(ulong index, ulong length, T[] destination, ulong destinationIndex)
|
||||
{
|
||||
var totalLength = Length;
|
||||
if (index >= totalLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("index");
|
||||
}
|
||||
|
||||
length = Math.Min(length, totalLength - index);
|
||||
return engine.ScriptInvoke(() =>
|
||||
{
|
||||
target.InvokeWithArrayBufferOrViewData(pData =>
|
||||
{
|
||||
length = UnmanagedMemoryHelpers.Copy(GetPtrWithIndex(pData, index), length, destination, destinationIndex);
|
||||
});
|
||||
|
||||
return length;
|
||||
});
|
||||
}
|
||||
|
||||
ulong ITypedArray<T>.Write(T[] source, ulong sourceIndex, ulong length, ulong index)
|
||||
{
|
||||
var totalLength = Length;
|
||||
if (index >= totalLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("index");
|
||||
}
|
||||
|
||||
length = Math.Min(length, totalLength - index);
|
||||
return engine.ScriptInvoke(() =>
|
||||
{
|
||||
target.InvokeWithArrayBufferOrViewData(pData =>
|
||||
{
|
||||
length = UnmanagedMemoryHelpers.Copy(source, sourceIndex, length, GetPtrWithIndex(pData, index));
|
||||
});
|
||||
|
||||
return length;
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: V8UInt16Array
|
||||
|
||||
// special case to support both ITypedArray<ushort> and ITypedArray<char>
|
||||
|
||||
private class V8UInt16Array : V8TypedArray<ushort>, ITypedArray<char>
|
||||
{
|
||||
public V8UInt16Array(V8ScriptEngine engine, IV8Object target)
|
||||
: base(engine, target)
|
||||
{
|
||||
}
|
||||
|
||||
#region ITypedArray<char> implementation
|
||||
|
||||
char[] ITypedArray<char>.ToArray()
|
||||
{
|
||||
return engine.ScriptInvoke(() =>
|
||||
{
|
||||
var result = new char[Length];
|
||||
target.InvokeWithArrayBufferOrViewData(pData =>
|
||||
{
|
||||
UnmanagedMemoryHelpers.Copy(pData, Length, result, 0);
|
||||
});
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
ulong ITypedArray<char>.Read(ulong index, ulong length, char[] destination, ulong destinationIndex)
|
||||
{
|
||||
var totalLength = Length;
|
||||
if (index >= totalLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("index");
|
||||
}
|
||||
|
||||
length = Math.Min(length, totalLength - index);
|
||||
return engine.ScriptInvoke(() =>
|
||||
{
|
||||
target.InvokeWithArrayBufferOrViewData(pData =>
|
||||
{
|
||||
length = UnmanagedMemoryHelpers.Copy(GetPtrWithIndex(pData, index), length, destination, destinationIndex);
|
||||
});
|
||||
|
||||
return length;
|
||||
});
|
||||
}
|
||||
|
||||
ulong ITypedArray<char>.Write(char[] source, ulong sourceIndex, ulong length, ulong index)
|
||||
{
|
||||
var totalLength = Length;
|
||||
if (index >= totalLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("index");
|
||||
}
|
||||
|
||||
length = Math.Min(length, totalLength - index);
|
||||
return engine.ScriptInvoke(() =>
|
||||
{
|
||||
target.InvokeWithArrayBufferOrViewData(pData =>
|
||||
{
|
||||
length = UnmanagedMemoryHelpers.Copy(source, sourceIndex, length, GetPtrWithIndex(pData, index));
|
||||
});
|
||||
|
||||
return length;
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -167,6 +167,11 @@ namespace Microsoft.ClearScript.Windows
|
|||
activeScriptProperty.SetProperty(ScriptProp.InvokeVersioning, IntPtr.Zero, ref value);
|
||||
}
|
||||
}
|
||||
|
||||
if (!flags.HasFlag(WindowsScriptEngineFlags.DoNotEnableVTablePatching) && MiscHelpers.IsX86InstructionSet())
|
||||
{
|
||||
HostItem.EnableVTablePatching = true;
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper restore SuspiciousTypeConversion.Global
|
||||
|
@ -313,6 +318,11 @@ namespace Microsoft.ClearScript.Windows
|
|||
activeScriptProperty.SetProperty(ScriptProp.InvokeVersioning, IntPtr.Zero, ref value);
|
||||
}
|
||||
}
|
||||
|
||||
if (!flags.HasFlag(WindowsScriptEngineFlags.DoNotEnableVTablePatching) && MiscHelpers.IsX86InstructionSet())
|
||||
{
|
||||
HostItem.EnableVTablePatching = true;
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper restore SuspiciousTypeConversion.Global
|
||||
|
|
|
@ -501,7 +501,7 @@ namespace Microsoft.ClearScript.Windows
|
|||
}
|
||||
|
||||
var hostTarget = obj as HostTarget;
|
||||
if (hostTarget != null)
|
||||
if ((hostTarget != null) && !(hostTarget is IHostVariable))
|
||||
{
|
||||
obj = hostTarget.Target;
|
||||
}
|
||||
|
|
|
@ -118,6 +118,17 @@ namespace Microsoft.ClearScript.Windows
|
|||
/// <see href="http://msdn.microsoft.com/en-us/library/y39d47w8(v=vs.84).aspx">VBArray</see>
|
||||
/// object to to access them.
|
||||
/// </summary>
|
||||
MarshalArraysByValue = 0x00000040
|
||||
MarshalArraysByValue = 0x00000040,
|
||||
|
||||
/// <summary>
|
||||
/// When <see cref="EnableStandardsMode"/> is specified, the ClearScript library uses
|
||||
/// virtual method table patching to support JScript-specific
|
||||
/// <see href="https://msdn.microsoft.com/en-us/library/sky96ah7(VS.94).aspx">IDispatchEx</see>
|
||||
/// extensions that otherwise interfere with some host object functionality. Virtual method
|
||||
/// table patching is a very low-level mechanism with global effect. This option specifies
|
||||
/// that virtual method table patching is not to be enabled on behalf of the current
|
||||
/// <see cref="JScriptEngine"/> instance.
|
||||
/// </summary>
|
||||
DoNotEnableVTablePatching = 0x00000080,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -229,7 +229,7 @@ namespace Microsoft.ClearScript.Windows
|
|||
|
||||
#region IDynamic implementation
|
||||
|
||||
public override object GetProperty(string name)
|
||||
public override object GetProperty(string name, object[] args)
|
||||
{
|
||||
VerifyNotDisposed();
|
||||
|
||||
|
@ -237,7 +237,7 @@ namespace Microsoft.ClearScript.Windows
|
|||
{
|
||||
try
|
||||
{
|
||||
return target.InvokeMember(name, BindingFlags.GetProperty, null, target, MiscHelpers.GetEmptyArray<object>(), null, CultureInfo.InvariantCulture, null);
|
||||
return target.InvokeMember(name, BindingFlags.GetProperty, null, target, engine.MarshalToScript(args), null, CultureInfo.InvariantCulture, null);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
@ -262,13 +262,13 @@ namespace Microsoft.ClearScript.Windows
|
|||
return result;
|
||||
}
|
||||
|
||||
public override void SetProperty(string name, object value)
|
||||
public override void SetProperty(string name, object[] args)
|
||||
{
|
||||
VerifyNotDisposed();
|
||||
|
||||
engine.ScriptInvoke(() =>
|
||||
{
|
||||
var marshaledArgs = new[] { engine.MarshalToScript(value) };
|
||||
var marshaledArgs = engine.MarshalToScript(args);
|
||||
try
|
||||
{
|
||||
target.InvokeMember(name, BindingFlags.SetProperty, null, target, marshaledArgs, null, CultureInfo.InvariantCulture, null);
|
||||
|
@ -314,13 +314,13 @@ namespace Microsoft.ClearScript.Windows
|
|||
public override object GetProperty(int index)
|
||||
{
|
||||
VerifyNotDisposed();
|
||||
return GetProperty(index.ToString(CultureInfo.InvariantCulture));
|
||||
return GetProperty(index.ToString(CultureInfo.InvariantCulture), MiscHelpers.GetEmptyArray<object>());
|
||||
}
|
||||
|
||||
public override void SetProperty(int index, object value)
|
||||
{
|
||||
VerifyNotDisposed();
|
||||
SetProperty(index.ToString(CultureInfo.InvariantCulture), value);
|
||||
SetProperty(index.ToString(CultureInfo.InvariantCulture), new[] { value });
|
||||
}
|
||||
|
||||
public override bool DeleteProperty(int index)
|
||||
|
|
Двоичные данные
ClearScript/doc/Reference.chm
Двоичные данные
ClearScript/doc/Reference.chm
Двоичный файл не отображается.
|
@ -8,7 +8,7 @@
|
|||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{5e8abcfa-8cbd-4d77-bfcc-d396e945a10e}</ProjectGuid>
|
||||
<SHFBSchemaVersion>1.9.9.0</SHFBSchemaVersion>
|
||||
<SHFBSchemaVersion>2015.6.5.0</SHFBSchemaVersion>
|
||||
<!-- AssemblyName, Name, and RootNamespace are not used by SHFB but Visual
|
||||
Studio adds them anyway -->
|
||||
<AssemblyName>Documentation</AssemblyName>
|
||||
|
@ -27,7 +27,7 @@
|
|||
<FeedbackEMailAddress>ClearScript%40microsoft.com</FeedbackEMailAddress>
|
||||
<FeedbackEMailLinkText>Microsoft</FeedbackEMailLinkText>
|
||||
<FrameworkVersion>.NET Framework 4.0</FrameworkVersion>
|
||||
<PresentationStyle>VS2010</PresentationStyle>
|
||||
<PresentationStyle>VS2013</PresentationStyle>
|
||||
<Preliminary>False</Preliminary>
|
||||
<BuildAssemblerVerbosity>OnlyWarningsAndErrors</BuildAssemblerVerbosity>
|
||||
<HelpFileFormat>HtmlHelp1</HelpFileFormat>
|
||||
|
@ -44,14 +44,15 @@
|
|||
<CopyrightText>Copyright &#169%3b Microsoft Corporation. All rights reserved.</CopyrightText>
|
||||
<NamespaceSummaries>
|
||||
<NamespaceSummaryItem name="Microsoft.ClearScript" isDocumented="True">The Microsoft.ClearScript namespace contains types that support all script engines.</NamespaceSummaryItem>
|
||||
<NamespaceSummaryItem name="Microsoft.ClearScript.V8" isDocumented="True">The Microsoft.ClearScript.V8 namespace contains types that provide access to the V8 high-performance open-source JavaScript engine.</NamespaceSummaryItem>
|
||||
<NamespaceSummaryItem name="Microsoft.ClearScript.Windows" isDocumented="True">The Microsoft.ClearScript.Windows namespace contains types that provide access to Windows Script engines such as JScript and VBScript.</NamespaceSummaryItem>
|
||||
<NamespaceSummaryItem name="(global)" isDocumented="False" />
|
||||
</NamespaceSummaries>
|
||||
<NamespaceSummaryItem name="Microsoft.ClearScript.V8" isDocumented="True">The Microsoft.ClearScript.V8 namespace contains types that provide access to the V8 high-performance open-source JavaScript engine.</NamespaceSummaryItem>
|
||||
<NamespaceSummaryItem name="Microsoft.ClearScript.Windows" isDocumented="True">The Microsoft.ClearScript.Windows namespace contains types that provide access to Windows Script engines such as JScript and VBScript.</NamespaceSummaryItem>
|
||||
<NamespaceSummaryItem name="(global)" isDocumented="False" />
|
||||
<NamespaceSummaryItem name="Microsoft.ClearScript.JavaScript" isDocumented="True">The Microsoft.ClearScript.JavaScript namespace contains types that provide access to JavaScript-specific features.</NamespaceSummaryItem></NamespaceSummaries>
|
||||
<RootNamespaceTitle>ClearScript Library Reference</RootNamespaceTitle>
|
||||
<ProjectSummary>The ClearScript library makes it easy to add scripting to your .NET applications.</ProjectSummary>
|
||||
<MaximumGroupParts>2</MaximumGroupParts>
|
||||
<NamespaceGrouping>False</NamespaceGrouping>
|
||||
<HelpFileVersion>1.0.0.0</HelpFileVersion>
|
||||
</PropertyGroup>
|
||||
<!-- There are no properties for these groups. AnyCPU needs to appear in
|
||||
order for Visual Studio to perform the build. The others are optional
|
||||
|
|
|
@ -69,5 +69,5 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCopyright("(c) Microsoft Corporation")]
|
||||
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: AssemblyVersion("5.4.3.0")]
|
||||
[assembly: AssemblyFileVersion("5.4.3.0")]
|
||||
[assembly: AssemblyVersion("5.4.4.0")]
|
||||
[assembly: AssemblyFileVersion("5.4.4.0")]
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace Microsoft.ClearScript.Test
|
|||
internal static class SunSpider
|
||||
{
|
||||
private const string version = "sunspider-1.0.2";
|
||||
private const string baseUrl = "http://www.webkit.org/perf/" + version + "/" + version + "/";
|
||||
private const string baseUrl = "https://webkit.org/perf/" + version + "/" + version + "/";
|
||||
|
||||
private const int repeatCount = 10;
|
||||
private const string scriptBegin = "<script>";
|
||||
|
|
|
@ -69,5 +69,5 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCopyright("(c) Microsoft Corporation")]
|
||||
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: AssemblyVersion("5.4.3.0")]
|
||||
[assembly: AssemblyFileVersion("5.4.3.0")]
|
||||
[assembly: AssemblyVersion("5.4.4.0")]
|
||||
[assembly: AssemblyFileVersion("5.4.4.0")]
|
||||
|
|
|
@ -1292,6 +1292,516 @@ namespace Microsoft.ClearScript.Test
|
|||
Assert.AreEqual("123 456.789 hello", engine.Evaluate("foo.RunTest(123, 456.789, 'hello')"));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("BugFix")]
|
||||
public void BugFix_NestedInterrupt()
|
||||
{
|
||||
var context = new PropertyBag();
|
||||
engine.AddHostObject("context", context);
|
||||
|
||||
using (var startEvent = new ManualResetEventSlim(false))
|
||||
{
|
||||
object result = null;
|
||||
var interruptedInner = false;
|
||||
var interruptedOuter = false;
|
||||
|
||||
context["startEvent"] = startEvent;
|
||||
context["foo"] = new Action(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
engine.Execute("while (true) { context.startEvent.Set(); }");
|
||||
}
|
||||
catch (ScriptInterruptedException)
|
||||
{
|
||||
interruptedInner = true;
|
||||
}
|
||||
});
|
||||
|
||||
var thread = new Thread(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
result = engine.Evaluate("context.foo(); 123");
|
||||
}
|
||||
catch (ScriptInterruptedException)
|
||||
{
|
||||
interruptedOuter = true;
|
||||
}
|
||||
});
|
||||
|
||||
thread.Start();
|
||||
startEvent.Wait();
|
||||
engine.Interrupt();
|
||||
thread.Join();
|
||||
|
||||
Assert.IsTrue(interruptedInner);
|
||||
Assert.IsFalse(interruptedOuter);
|
||||
Assert.AreEqual(123, result);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("BugFix")]
|
||||
public void BugFix_NestedInterrupt_JScript()
|
||||
{
|
||||
engine.Dispose();
|
||||
try
|
||||
{
|
||||
using (var startEvent = new ManualResetEventSlim(false))
|
||||
{
|
||||
object result = null;
|
||||
var interruptedInner = false;
|
||||
var interruptedOuter = false;
|
||||
|
||||
var thread = new Thread(() =>
|
||||
{
|
||||
using (engine = new JScriptEngine(WindowsScriptEngineFlags.EnableDebugging))
|
||||
{
|
||||
var context = new PropertyBag();
|
||||
engine.AddHostObject("context", context);
|
||||
|
||||
// ReSharper disable once AccessToDisposedClosure
|
||||
context["startEvent"] = startEvent;
|
||||
context["foo"] = new Action(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
engine.Execute("while (true) { context.startEvent.Set(); }");
|
||||
}
|
||||
catch (ScriptInterruptedException)
|
||||
{
|
||||
interruptedInner = true;
|
||||
}
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
result = engine.Evaluate("context.foo(); 123");
|
||||
}
|
||||
catch (ScriptInterruptedException)
|
||||
{
|
||||
interruptedOuter = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
thread.Start();
|
||||
startEvent.Wait();
|
||||
engine.Interrupt();
|
||||
thread.Join();
|
||||
|
||||
Assert.IsTrue(interruptedInner);
|
||||
Assert.IsFalse(interruptedOuter);
|
||||
Assert.AreEqual(123, result);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
engine = new V8ScriptEngine(V8ScriptEngineFlags.EnableDebugging);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("BugFix")]
|
||||
public void BugFix_PropertyBag_NativeEnumerator_JScript()
|
||||
{
|
||||
engine.Dispose();
|
||||
engine = new JScriptEngine();
|
||||
|
||||
var x = new PropertyBag();
|
||||
x["foo"] = 123;
|
||||
x["bar"] = "blah";
|
||||
engine.Script.x = x;
|
||||
|
||||
var result = (string)engine.Evaluate(@"
|
||||
var result = '';
|
||||
for (var e = new Enumerator(x); !e.atEnd(); e.moveNext()) {
|
||||
result += e.item().Value;
|
||||
}
|
||||
result
|
||||
");
|
||||
|
||||
Assert.AreEqual(7, result.Length);
|
||||
Assert.IsTrue(result.IndexOf("123", StringComparison.Ordinal) >= 0);
|
||||
Assert.IsTrue(result.IndexOf("blah", StringComparison.Ordinal) >= 0);
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("BugFix")]
|
||||
public void BugFix_PropertyBag_NativeEnumerator_VBScript()
|
||||
{
|
||||
engine.Dispose();
|
||||
engine = new VBScriptEngine();
|
||||
|
||||
var x = new PropertyBag();
|
||||
x["foo"] = 123;
|
||||
x["bar"] = "blah";
|
||||
engine.Script.x = x;
|
||||
|
||||
engine.Execute(@"
|
||||
function getResult(arg)
|
||||
dim result
|
||||
result = """"
|
||||
for each item in arg
|
||||
result = result & item.Value
|
||||
next
|
||||
getResult = result
|
||||
end function
|
||||
");
|
||||
|
||||
var result = (string)engine.Evaluate("getResult(x)");
|
||||
|
||||
Assert.AreEqual(7, result.Length);
|
||||
Assert.IsTrue(result.IndexOf("123", StringComparison.Ordinal) >= 0);
|
||||
Assert.IsTrue(result.IndexOf("blah", StringComparison.Ordinal) >= 0);
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("BugFix")]
|
||||
public void BugFix_JScriptStandardsMode_PropertyAccess()
|
||||
{
|
||||
engine.Dispose();
|
||||
engine = new JScriptEngine(WindowsScriptEngineFlags.EnableStandardsMode);
|
||||
engine.Script.x = new { foo = 123 };
|
||||
Assert.AreEqual(123, engine.Evaluate("x.foo"));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("BugFix")]
|
||||
public void BugFix_JScriptStandardsMode_MemberEnumeration()
|
||||
{
|
||||
engine.Dispose();
|
||||
engine = new JScriptEngine(WindowsScriptEngineFlags.EnableStandardsMode);
|
||||
|
||||
engine.Script.x = new { foo = 123, bar = "blah" };
|
||||
var result = (string)engine.Evaluate(@"
|
||||
var result = '';
|
||||
for (var i in x) {
|
||||
if ((i == 'foo') || (i == 'bar')) {
|
||||
result += x[i];
|
||||
}
|
||||
}
|
||||
result
|
||||
");
|
||||
|
||||
Assert.AreEqual(7, result.Length);
|
||||
Assert.IsTrue(result.IndexOf("123", StringComparison.Ordinal) >= 0);
|
||||
Assert.IsTrue(result.IndexOf("blah", StringComparison.Ordinal) >= 0);
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("BugFix")]
|
||||
public void BugFix_JScriptStandardsMode_MemberEnumeration_PropertyBag()
|
||||
{
|
||||
engine.Dispose();
|
||||
engine = new JScriptEngine(WindowsScriptEngineFlags.EnableStandardsMode);
|
||||
|
||||
var x = new PropertyBag();
|
||||
x["foo"] = 123;
|
||||
x["bar"] = "blah";
|
||||
engine.Script.x = x;
|
||||
|
||||
var result = (string)engine.Evaluate(@"
|
||||
var result = '';
|
||||
for (var i in x) {
|
||||
result += x[i];
|
||||
}
|
||||
result
|
||||
");
|
||||
|
||||
Assert.AreEqual(7, result.Length);
|
||||
Assert.IsTrue(result.IndexOf("123", StringComparison.Ordinal) >= 0);
|
||||
Assert.IsTrue(result.IndexOf("blah", StringComparison.Ordinal) >= 0);
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("BugFix")]
|
||||
public void BugFix_JScriptStandardsMode_MemberEnumeration_Dynamic()
|
||||
{
|
||||
engine.Dispose();
|
||||
engine = new JScriptEngine(WindowsScriptEngineFlags.EnableStandardsMode);
|
||||
|
||||
dynamic x = new ExpandoObject();
|
||||
x.foo = 123;
|
||||
x.bar = "blah";
|
||||
engine.Script.x = x;
|
||||
|
||||
var result = (string)engine.Evaluate(@"
|
||||
var result = '';
|
||||
for (var i in x) {
|
||||
if ((i == 'foo') || (i == 'bar')) {
|
||||
result += x[i];
|
||||
}
|
||||
}
|
||||
result
|
||||
");
|
||||
|
||||
Assert.AreEqual(7, result.Length);
|
||||
Assert.IsTrue(result.IndexOf("123", StringComparison.Ordinal) >= 0);
|
||||
Assert.IsTrue(result.IndexOf("blah", StringComparison.Ordinal) >= 0);
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("BugFix")]
|
||||
public void BugFix_JScriptStandardsMode_MemberDeletion_PropertyBag()
|
||||
{
|
||||
engine.Dispose();
|
||||
engine = new JScriptEngine(WindowsScriptEngineFlags.EnableStandardsMode);
|
||||
|
||||
var x = new PropertyBag();
|
||||
x["foo"] = 123;
|
||||
x["bar"] = "blah";
|
||||
engine.Script.x = x;
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("x.foo"));
|
||||
Assert.AreEqual("blah", engine.Evaluate("x.bar"));
|
||||
Assert.AreEqual(true, engine.Evaluate("delete x.foo"));
|
||||
Assert.IsInstanceOfType(engine.Evaluate("x.foo"), typeof(Undefined));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("BugFix")]
|
||||
public void BugFix_JScriptStandardsMode_MemberDeletion_Dynamic()
|
||||
{
|
||||
engine.Dispose();
|
||||
engine = new JScriptEngine(WindowsScriptEngineFlags.EnableStandardsMode);
|
||||
|
||||
dynamic x = new ExpandoObject();
|
||||
x.foo = 123;
|
||||
x.bar = "blah";
|
||||
engine.Script.x = x;
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("x.foo"));
|
||||
Assert.AreEqual("blah", engine.Evaluate("x.bar"));
|
||||
Assert.AreEqual(true, engine.Evaluate("delete x.foo"));
|
||||
Assert.IsInstanceOfType(engine.Evaluate("x.foo"), typeof(Undefined));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("BugFix")]
|
||||
public void BugFix_NumericArgConversion_Delegate()
|
||||
{
|
||||
engine.Script.host = new HostFunctions();
|
||||
engine.Script.sbyteFunc = new Func<sbyte, sbyte>(arg => arg);
|
||||
engine.Script.nullableSByteFunc = new Func<sbyte?, sbyte?>(arg => arg);
|
||||
engine.Script.floatFunc = new Func<float, float>(arg => arg);
|
||||
engine.Script.nullableFloatFunc = new Func<float?, float?>(arg => arg);
|
||||
engine.Script.doubleFunc = new Func<double, double>(arg => arg);
|
||||
engine.Script.nullableDoubleFunc = new Func<double?, double?>(arg => arg);
|
||||
engine.Script.decimalFunc = new Func<decimal, decimal>(arg => arg);
|
||||
engine.Script.nullableDecimalFunc = new Func<decimal?, decimal?>(arg => arg);
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("sbyteFunc(123)"));
|
||||
TestUtil.AssertException<OverflowException>(() => engine.Execute("sbyteFunc(234)"));
|
||||
TestUtil.AssertException<ArgumentException>(() => engine.Execute("sbyteFunc(123.5)"));
|
||||
TestUtil.AssertException<ArgumentException>(() => engine.Execute("sbyteFunc(Math.PI)"));
|
||||
TestUtil.AssertException<ArgumentException>(() => engine.Execute("sbyteFunc(host.toDecimal(Math.PI))"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("nullableSByteFunc(123)"));
|
||||
TestUtil.AssertException<OverflowException>(() => engine.Execute("nullableSByteFunc(234)"));
|
||||
TestUtil.AssertException<ArgumentException>(() => engine.Execute("nullableSByteFunc(123.5)"));
|
||||
TestUtil.AssertException<ArgumentException>(() => engine.Execute("nullableSByteFunc(Math.PI)"));
|
||||
TestUtil.AssertException<ArgumentException>(() => engine.Execute("nullableSByteFunc(host.toDecimal(Math.PI))"));
|
||||
Assert.IsNull(engine.Evaluate("nullableSByteFunc(null)"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("floatFunc(123)"));
|
||||
Assert.AreEqual(123.5f, engine.Evaluate("floatFunc(123.5)"));
|
||||
Assert.AreEqual((float)Math.PI, engine.Evaluate("floatFunc(Math.PI)"));
|
||||
Assert.AreEqual((float)Math.PI, engine.Evaluate("floatFunc(host.toDecimal(Math.PI))"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("nullableFloatFunc(123)"));
|
||||
Assert.AreEqual(123.5f, engine.Evaluate("nullableFloatFunc(123.5)"));
|
||||
Assert.AreEqual((float)Math.PI, engine.Evaluate("nullableFloatFunc(Math.PI)"));
|
||||
Assert.AreEqual((float)Math.PI, engine.Evaluate("nullableFloatFunc(host.toDecimal(Math.PI))"));
|
||||
Assert.IsNull(engine.Evaluate("nullableFloatFunc(null)"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("doubleFunc(123)"));
|
||||
Assert.AreEqual(123.5f, engine.Evaluate("doubleFunc(123.5)"));
|
||||
Assert.AreEqual(Math.PI, engine.Evaluate("doubleFunc(Math.PI)"));
|
||||
Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("doubleFunc(host.toDecimal(Math.PI))"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("nullableDoubleFunc(123)"));
|
||||
Assert.AreEqual(123.5f, engine.Evaluate("nullableDoubleFunc(123.5)"));
|
||||
Assert.AreEqual(Math.PI, engine.Evaluate("nullableDoubleFunc(Math.PI)"));
|
||||
Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("nullableDoubleFunc(host.toDecimal(Math.PI))"));
|
||||
Assert.IsNull(engine.Evaluate("nullableDoubleFunc(null)"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("decimalFunc(123)"));
|
||||
Assert.AreEqual(123.5f, engine.Evaluate("decimalFunc(123.5)"));
|
||||
Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("decimalFunc(Math.PI)"));
|
||||
Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("decimalFunc(host.toDecimal(Math.PI))"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("nullableDecimalFunc(123)"));
|
||||
Assert.AreEqual(123.5f, engine.Evaluate("nullableDecimalFunc(123.5)"));
|
||||
Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("nullableDecimalFunc(Math.PI)"));
|
||||
Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("nullableDecimalFunc(host.toDecimal(Math.PI))"));
|
||||
Assert.IsNull(engine.Evaluate("nullableDecimalFunc(null)"));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("BugFix")]
|
||||
public void BugFix_NumericArgConversion_Field()
|
||||
{
|
||||
engine.Script.host = new HostFunctions();
|
||||
engine.Script.test = new NumericArgConversionTest();
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.SByteField = 123; test.SByteField"));
|
||||
TestUtil.AssertException<OverflowException>(() => engine.Execute("test.SByteField = 234"));
|
||||
TestUtil.AssertException<ArgumentException>(() => engine.Execute("test.SByteField = 123.5"));
|
||||
TestUtil.AssertException<ArgumentException>(() => engine.Execute("test.SByteField = Math.PI"));
|
||||
TestUtil.AssertException<ArgumentException>(() => engine.Execute("test.SByteField = host.toDecimal(Math.PI)"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.NullableSByteField = 123; test.NullableSByteField"));
|
||||
TestUtil.AssertException<OverflowException>(() => engine.Execute("test.NullableSByteField = 234"));
|
||||
TestUtil.AssertException<ArgumentException>(() => engine.Execute("test.NullableSByteField = 123.5"));
|
||||
TestUtil.AssertException<ArgumentException>(() => engine.Execute("test.NullableSByteField = Math.PI"));
|
||||
TestUtil.AssertException<ArgumentException>(() => engine.Execute("test.NullableSByteField = host.toDecimal(Math.PI)"));
|
||||
Assert.IsNull(engine.Evaluate("test.NullableSByteField = null; test.NullableSByteField"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.FloatField = 123; test.FloatField"));
|
||||
Assert.AreEqual(123.5f, engine.Evaluate("test.FloatField = 123.5; test.FloatField"));
|
||||
Assert.AreEqual((float)Math.PI, engine.Evaluate("test.FloatField = Math.PI; test.FloatField"));
|
||||
Assert.AreEqual((float)Math.PI, engine.Evaluate("test.FloatField = host.toDecimal(Math.PI); test.FloatField"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.NullableFloatField = 123; test.NullableFloatField"));
|
||||
Assert.AreEqual(123.5f, engine.Evaluate("test.NullableFloatField = 123.5; test.NullableFloatField"));
|
||||
Assert.AreEqual((float)Math.PI, engine.Evaluate("test.NullableFloatField = Math.PI; test.NullableFloatField"));
|
||||
Assert.AreEqual((float)Math.PI, engine.Evaluate("test.NullableFloatField = host.toDecimal(Math.PI); test.NullableFloatField"));
|
||||
Assert.IsNull(engine.Evaluate("test.NullableFloatField = null; test.NullableFloatField"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.DoubleField = 123; test.DoubleField"));
|
||||
Assert.AreEqual(123.5f, engine.Evaluate("test.DoubleField = 123.5; test.DoubleField"));
|
||||
Assert.AreEqual(Math.PI, engine.Evaluate("test.DoubleField = Math.PI; test.DoubleField"));
|
||||
Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.DoubleField = host.toDecimal(Math.PI); test.DoubleField"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.NullableDoubleField = 123; test.NullableDoubleField"));
|
||||
Assert.AreEqual(123.5f, engine.Evaluate("test.NullableDoubleField = 123.5; test.NullableDoubleField"));
|
||||
Assert.AreEqual(Math.PI, engine.Evaluate("test.NullableDoubleField = Math.PI; test.NullableDoubleField"));
|
||||
Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.NullableDoubleField = host.toDecimal(Math.PI); test.NullableDoubleField"));
|
||||
Assert.IsNull(engine.Evaluate("test.NullableDoubleField = null; test.NullableDoubleField"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.DecimalField = 123; test.DecimalField"));
|
||||
Assert.AreEqual(123.5f, engine.Evaluate("test.DecimalField = 123.5; test.DecimalField"));
|
||||
Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.DecimalField = Math.PI; test.DecimalField"));
|
||||
Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.DecimalField = host.toDecimal(Math.PI); test.DecimalField"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.NullableDecimalField = 123; test.NullableDecimalField"));
|
||||
Assert.AreEqual(123.5f, engine.Evaluate("test.NullableDecimalField = 123.5; test.NullableDecimalField"));
|
||||
Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.NullableDecimalField = Math.PI; test.NullableDecimalField"));
|
||||
Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.NullableDecimalField = host.toDecimal(Math.PI); test.NullableDecimalField"));
|
||||
Assert.IsNull(engine.Evaluate("test.NullableDecimalField = null; test.NullableDecimalField"));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("BugFix")]
|
||||
public void BugFix_NumericArgConversion_Method()
|
||||
{
|
||||
engine.Script.host = new HostFunctions();
|
||||
engine.Script.test = new NumericArgConversionTest();
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.SByteMethod(123)"));
|
||||
TestUtil.AssertException<OverflowException>(() => engine.Execute("test.SByteMethod(234)"));
|
||||
TestUtil.AssertException<RuntimeBinderException>(() => engine.Execute("test.SByteMethod(123.5)"));
|
||||
TestUtil.AssertException<RuntimeBinderException>(() => engine.Execute("test.SByteMethod(Math.PI)"));
|
||||
TestUtil.AssertException<RuntimeBinderException>(() => engine.Execute("test.SByteMethod(host.toDecimal(Math.PI))"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.NullableSByteMethod(123)"));
|
||||
TestUtil.AssertException<OverflowException>(() => engine.Execute("test.NullableSByteMethod(234)"));
|
||||
TestUtil.AssertException<RuntimeBinderException>(() => engine.Execute("test.NullableSByteMethod(123.5)"));
|
||||
TestUtil.AssertException<RuntimeBinderException>(() => engine.Execute("test.NullableSByteMethod(Math.PI)"));
|
||||
TestUtil.AssertException<RuntimeBinderException>(() => engine.Execute("test.NullableSByteMethod(host.toDecimal(Math.PI))"));
|
||||
Assert.IsNull(engine.Evaluate("test.NullableSByteMethod(null)"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.FloatMethod(123)"));
|
||||
Assert.AreEqual(123.5f, engine.Evaluate("test.FloatMethod(123.5)"));
|
||||
TestUtil.AssertException<RuntimeBinderException>(() => engine.Execute("test.FloatMethod(Math.PI)"));
|
||||
TestUtil.AssertException<RuntimeBinderException>(() => engine.Execute("test.FloatMethod(host.toDecimal(Math.PI))"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.NullableFloatMethod(123)"));
|
||||
Assert.AreEqual(123.5f, engine.Evaluate("test.NullableFloatMethod(123.5)"));
|
||||
TestUtil.AssertException<RuntimeBinderException>(() => engine.Execute("test.NullableFloatMethod(Math.PI)"));
|
||||
TestUtil.AssertException<RuntimeBinderException>(() => engine.Execute("test.NullableFloatMethod(host.toDecimal(Math.PI))"));
|
||||
Assert.IsNull(engine.Evaluate("test.NullableFloatMethod(null)"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.DoubleMethod(123)"));
|
||||
Assert.AreEqual(123.5f, engine.Evaluate("test.DoubleMethod(123.5)"));
|
||||
Assert.AreEqual(Math.PI, engine.Evaluate("test.DoubleMethod(Math.PI)"));
|
||||
TestUtil.AssertException<RuntimeBinderException>(() => engine.Execute("test.DoubleMethod(host.toDecimal(Math.PI))"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.NullableDoubleMethod(123)"));
|
||||
Assert.AreEqual(123.5f, engine.Evaluate("test.NullableDoubleMethod(123.5)"));
|
||||
Assert.AreEqual(Math.PI, engine.Evaluate("test.NullableDoubleMethod(Math.PI)"));
|
||||
TestUtil.AssertException<RuntimeBinderException>(() => engine.Execute("test.NullableDoubleMethod(host.toDecimal(Math.PI))"));
|
||||
Assert.IsNull(engine.Evaluate("test.NullableDoubleMethod(null)"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.DecimalMethod(123)"));
|
||||
TestUtil.AssertException<RuntimeBinderException>(() => engine.Execute("test.DecimalMethod(123.5)"));
|
||||
TestUtil.AssertException<RuntimeBinderException>(() => engine.Execute("test.DecimalMethod(Math.PI)"));
|
||||
Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.DecimalMethod(host.toDecimal(Math.PI))"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.NullableDecimalMethod(123)"));
|
||||
TestUtil.AssertException<RuntimeBinderException>(() => engine.Execute("test.NullableDecimalMethod(123.5)"));
|
||||
TestUtil.AssertException<RuntimeBinderException>(() => engine.Execute("test.NullableDecimalMethod(Math.PI)"));
|
||||
Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.NullableDecimalMethod(host.toDecimal(Math.PI))"));
|
||||
Assert.IsNull(engine.Evaluate("test.NullableDecimalMethod(null)"));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("BugFix")]
|
||||
public void BugFix_NumericArgConversion_Property()
|
||||
{
|
||||
engine.Script.host = new HostFunctions();
|
||||
engine.Script.test = new NumericArgConversionTest();
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.SByteProperty = 123; test.SByteProperty"));
|
||||
TestUtil.AssertException<OverflowException>(() => engine.Execute("test.SByteProperty = 234"));
|
||||
TestUtil.AssertException<ArgumentException>(() => engine.Execute("test.SByteProperty = 123.5"));
|
||||
TestUtil.AssertException<ArgumentException>(() => engine.Execute("test.SByteProperty = Math.PI"));
|
||||
TestUtil.AssertException<ArgumentException>(() => engine.Execute("test.SByteProperty = host.toDecimal(Math.PI)"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.NullableSByteProperty = 123; test.NullableSByteProperty"));
|
||||
TestUtil.AssertException<OverflowException>(() => engine.Execute("test.NullableSByteProperty = 234"));
|
||||
TestUtil.AssertException<ArgumentException>(() => engine.Execute("test.NullableSByteProperty = 123.5"));
|
||||
TestUtil.AssertException<ArgumentException>(() => engine.Execute("test.NullableSByteProperty = Math.PI"));
|
||||
TestUtil.AssertException<ArgumentException>(() => engine.Execute("test.NullableSByteProperty = host.toDecimal(Math.PI)"));
|
||||
Assert.IsNull(engine.Evaluate("test.NullableSByteProperty = null; test.NullableSByteProperty"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.FloatProperty = 123; test.FloatProperty"));
|
||||
Assert.AreEqual(123.5f, engine.Evaluate("test.FloatProperty = 123.5; test.FloatProperty"));
|
||||
Assert.AreEqual((float)Math.PI, engine.Evaluate("test.FloatProperty = Math.PI; test.FloatProperty"));
|
||||
Assert.AreEqual((float)Math.PI, engine.Evaluate("test.FloatProperty = host.toDecimal(Math.PI); test.FloatProperty"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.NullableFloatProperty = 123; test.NullableFloatProperty"));
|
||||
Assert.AreEqual(123.5f, engine.Evaluate("test.NullableFloatProperty = 123.5; test.NullableFloatProperty"));
|
||||
Assert.AreEqual((float)Math.PI, engine.Evaluate("test.NullableFloatProperty = Math.PI; test.NullableFloatProperty"));
|
||||
Assert.AreEqual((float)Math.PI, engine.Evaluate("test.NullableFloatProperty = host.toDecimal(Math.PI); test.NullableFloatProperty"));
|
||||
Assert.IsNull(engine.Evaluate("test.NullableFloatProperty = null; test.NullableFloatProperty"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.DoubleProperty = 123; test.DoubleProperty"));
|
||||
Assert.AreEqual(123.5f, engine.Evaluate("test.DoubleProperty = 123.5; test.DoubleProperty"));
|
||||
Assert.AreEqual(Math.PI, engine.Evaluate("test.DoubleProperty = Math.PI; test.DoubleProperty"));
|
||||
Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.DoubleProperty = host.toDecimal(Math.PI); test.DoubleProperty"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.NullableDoubleProperty = 123; test.NullableDoubleProperty"));
|
||||
Assert.AreEqual(123.5f, engine.Evaluate("test.NullableDoubleProperty = 123.5; test.NullableDoubleProperty"));
|
||||
Assert.AreEqual(Math.PI, engine.Evaluate("test.NullableDoubleProperty = Math.PI; test.NullableDoubleProperty"));
|
||||
Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.NullableDoubleProperty = host.toDecimal(Math.PI); test.NullableDoubleProperty"));
|
||||
Assert.IsNull(engine.Evaluate("test.NullableDoubleProperty = null; test.NullableDoubleProperty"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.DecimalProperty = 123; test.DecimalProperty"));
|
||||
Assert.AreEqual(123.5f, engine.Evaluate("test.DecimalProperty = 123.5; test.DecimalProperty"));
|
||||
Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.DecimalProperty = Math.PI; test.DecimalProperty"));
|
||||
Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.DecimalProperty = host.toDecimal(Math.PI); test.DecimalProperty"));
|
||||
|
||||
Assert.AreEqual(123, engine.Evaluate("test.NullableDecimalProperty = 123; test.NullableDecimalProperty"));
|
||||
Assert.AreEqual(123.5f, engine.Evaluate("test.NullableDecimalProperty = 123.5; test.NullableDecimalProperty"));
|
||||
Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.NullableDecimalProperty = Math.PI; test.NullableDecimalProperty"));
|
||||
Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.NullableDecimalProperty = host.toDecimal(Math.PI); test.NullableDecimalProperty"));
|
||||
Assert.IsNull(engine.Evaluate("test.NullableDecimalProperty = null; test.NullableDecimalProperty"));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("BugFix")]
|
||||
public void BugFix_ScriptObjectInHostVariable()
|
||||
{
|
||||
engine.Script.host = new HostFunctions();
|
||||
Assert.IsTrue(engine.Evaluate(null, true, "host.newVar({})", false).ToString().StartsWith("[HostVariable:", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("BugFix")]
|
||||
public void BugFix_ScriptObjectInHostVariable_JScript()
|
||||
{
|
||||
engine.Dispose();
|
||||
engine = new JScriptEngine();
|
||||
BugFix_ScriptObjectInHostVariable();
|
||||
}
|
||||
|
||||
// ReSharper restore InconsistentNaming
|
||||
|
||||
#endregion
|
||||
|
@ -1480,6 +1990,36 @@ namespace Microsoft.ClearScript.Test
|
|||
}
|
||||
}
|
||||
|
||||
public class NumericArgConversionTest
|
||||
{
|
||||
public sbyte SByteField;
|
||||
public sbyte? NullableSByteField;
|
||||
public float FloatField;
|
||||
public float? NullableFloatField;
|
||||
public double DoubleField;
|
||||
public double? NullableDoubleField;
|
||||
public decimal DecimalField;
|
||||
public decimal? NullableDecimalField;
|
||||
|
||||
public sbyte SByteMethod(sbyte arg) { return arg; }
|
||||
public sbyte? NullableSByteMethod(sbyte? arg) { return arg; }
|
||||
public float FloatMethod(float arg) { return arg; }
|
||||
public float? NullableFloatMethod(float? arg) { return arg; }
|
||||
public double DoubleMethod(double arg) { return arg; }
|
||||
public double? NullableDoubleMethod(double? arg) { return arg; }
|
||||
public decimal DecimalMethod(decimal arg) { return arg; }
|
||||
public decimal? NullableDecimalMethod(decimal? arg) { return arg; }
|
||||
|
||||
public sbyte SByteProperty { get; set; }
|
||||
public sbyte? NullableSByteProperty { get; set; }
|
||||
public float FloatProperty { get; set; }
|
||||
public float? NullableFloatProperty { get; set; }
|
||||
public double DoubleProperty { get; set; }
|
||||
public double? NullableDoubleProperty { get; set; }
|
||||
public decimal DecimalProperty { get; set; }
|
||||
public decimal? NullableDecimalProperty { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,6 +96,7 @@
|
|||
<Compile Include="StaticTestClass.cs" />
|
||||
<Compile Include="TestObject.cs" />
|
||||
<Compile Include="TypeRestrictionTest.cs" />
|
||||
<Compile Include="V8ArrayBufferOrViewTest.cs" />
|
||||
<Compile Include="V8ScriptEngineTest.cs" />
|
||||
<Compile Include="VBScriptEngineTest.cs" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -116,6 +116,8 @@ namespace Microsoft.ClearScript.Test
|
|||
|
||||
internal static void Test(HostTypeCollection typeCollection, string[] assemblyNames, Predicate<Type> filter, Func<Type, Type, bool> comparer)
|
||||
{
|
||||
// ReSharper disable CollectionNeverQueried.Local
|
||||
|
||||
typeCollection = typeCollection ?? new HostTypeCollection(filter, assemblyNames);
|
||||
var allNodes = GetLeafNodes(typeCollection).OrderBy(hostType => hostType.Type.GetLocator());
|
||||
|
||||
|
@ -138,6 +140,8 @@ namespace Microsoft.ClearScript.Test
|
|||
{
|
||||
Assert.IsTrue(allNodes.All(hostType => hostType.Types.All(type => filter(type))));
|
||||
}
|
||||
|
||||
// ReSharper restore CollectionNeverQueried.Local
|
||||
}
|
||||
|
||||
private static IEnumerable<Type> GetImportableTypes(string[] assemblyNames, Predicate<Type> filter)
|
||||
|
|
|
@ -2050,6 +2050,70 @@ namespace Microsoft.ClearScript.Test
|
|||
TestUtil.AssertException<RuntimeBinderException>(() => engine.Evaluate("listDict.Count()"));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("JScriptEngine")]
|
||||
public void JScriptEngine_NativeEnumerator()
|
||||
{
|
||||
var array = Enumerable.Range(0, 10).ToArray();
|
||||
engine.Execute(@"
|
||||
function sum(array) {
|
||||
var result = 0;
|
||||
for (var e = new Enumerator(array); !e.atEnd(); e.moveNext()) {
|
||||
result += e.item();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
");
|
||||
Assert.AreEqual(array.Aggregate((current, next) => current + next), engine.Script.sum(array));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("JScriptEngine")]
|
||||
public void JScriptEngine_NativeEnumerator_Generic()
|
||||
{
|
||||
var array = Enumerable.Range(0, 10).Select(value => (IConvertible)value).ToArray();
|
||||
engine.Script.culture = CultureInfo.InvariantCulture;
|
||||
engine.Execute(@"
|
||||
function sum(array) {
|
||||
var result = 0;
|
||||
for (var e = new Enumerator(array); !e.atEnd(); e.moveNext()) {
|
||||
result += e.item().ToInt32(culture);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
");
|
||||
Assert.AreEqual(array.Aggregate((current, next) => Convert.ToInt32(current) + Convert.ToInt32(next)), engine.Script.sum(array));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("JScriptEngine")]
|
||||
public void JScriptEngine_NativeEnumerator_NonGeneric()
|
||||
{
|
||||
var array = Enumerable.Range(0, 10).ToArray();
|
||||
engine.Execute(@"
|
||||
function sum(array) {
|
||||
var result = 0;
|
||||
for (var e = new Enumerator(array); !e.atEnd(); e.moveNext()) {
|
||||
result += e.item();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
");
|
||||
Assert.AreEqual(array.Aggregate((current, next) => current + next), engine.Script.sum(HostObject.Wrap(array, typeof(IEnumerable))));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("JScriptEngine")]
|
||||
public void JScriptEngine_NativeEnumerator_NonEnumerable()
|
||||
{
|
||||
engine.Execute(@"
|
||||
function sum(array) {
|
||||
var result = 0;
|
||||
for (var e = new Enumerator(array); !e.atEnd(); e.moveNext()) {
|
||||
result += e.item();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
");
|
||||
TestUtil.AssertException<ScriptEngineException>(() => engine.Script.sum(DayOfWeek.Monday));
|
||||
}
|
||||
|
||||
// ReSharper restore InconsistentNaming
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -69,5 +69,5 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCopyright("(c) Microsoft Corporation")]
|
||||
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: AssemblyVersion("5.4.3.0")]
|
||||
[assembly: AssemblyFileVersion("5.4.3.0")]
|
||||
[assembly: AssemblyVersion("5.4.4.0")]
|
||||
[assembly: AssemblyFileVersion("5.4.4.0")]
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1144,7 +1144,7 @@ namespace Microsoft.ClearScript.Test
|
|||
public void V8ScriptEngine_MaxRuntimeHeapSize_Dual()
|
||||
{
|
||||
const int limit = 4 * 1024 * 1024;
|
||||
const string code = @"x = []; for (i = 0; i < 8 * 1024 * 1024; i++) { x.push(x); }";
|
||||
const string code = @"x = []; for (i = 0; i < 16 * 1024 * 1024; i++) { x.push(x); }";
|
||||
|
||||
engine.Execute(code);
|
||||
engine.CollectGarbage(true);
|
||||
|
@ -2225,6 +2225,70 @@ namespace Microsoft.ClearScript.Test
|
|||
Assert.IsInstanceOfType(engine.Evaluate("foo.toFunction"), typeof(Undefined));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("V8ScriptEngine")]
|
||||
public void V8ScriptEngine_NativeEnumerator()
|
||||
{
|
||||
var array = Enumerable.Range(0, 10).ToArray();
|
||||
engine.Execute(@"
|
||||
function sum(array) {
|
||||
var result = 0;
|
||||
for (var item of array) {
|
||||
result += item;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
");
|
||||
Assert.AreEqual(array.Aggregate((current, next) => current + next), engine.Script.sum(array));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("V8ScriptEngine")]
|
||||
public void V8ScriptEngine_NativeEnumerator_Generic()
|
||||
{
|
||||
var array = Enumerable.Range(0, 10).Select(value => (IConvertible)value).ToArray();
|
||||
engine.Script.culture = CultureInfo.InvariantCulture;
|
||||
engine.Execute(@"
|
||||
function sum(array) {
|
||||
var result = 0;
|
||||
for (var item of array) {
|
||||
result += item.ToInt32(culture);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
");
|
||||
Assert.AreEqual(array.Aggregate((current, next) => Convert.ToInt32(current) + Convert.ToInt32(next)), engine.Script.sum(array));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("V8ScriptEngine")]
|
||||
public void V8ScriptEngine_NativeEnumerator_NonGeneric()
|
||||
{
|
||||
var array = Enumerable.Range(0, 10).ToArray();
|
||||
engine.Execute(@"
|
||||
function sum(array) {
|
||||
var result = 0;
|
||||
for (var item of array) {
|
||||
result += item;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
");
|
||||
Assert.AreEqual(array.Aggregate((current, next) => current + next), engine.Script.sum(HostObject.Wrap(array, typeof(IEnumerable))));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("V8ScriptEngine")]
|
||||
public void V8ScriptEngine_NativeEnumerator_NonEnumerable()
|
||||
{
|
||||
engine.Execute(@"
|
||||
function sum(array) {
|
||||
var result = 0;
|
||||
for (var item of array) {
|
||||
result += item;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
");
|
||||
TestUtil.AssertException<NotSupportedException>(() => engine.Script.sum(DayOfWeek.Monday));
|
||||
}
|
||||
|
||||
// ReSharper restore InconsistentNaming
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -2208,6 +2208,74 @@ namespace Microsoft.ClearScript.Test
|
|||
TestUtil.AssertException<RuntimeBinderException>(() => engine.Evaluate("listDict.Count()"));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("VBScriptEngine")]
|
||||
public void VBScriptEngine_NativeEnumerator()
|
||||
{
|
||||
var array = Enumerable.Range(0, 10).ToArray();
|
||||
engine.Execute(@"
|
||||
function sum(array)
|
||||
dim result
|
||||
result = 0
|
||||
for each item in array
|
||||
result = result + item
|
||||
next
|
||||
sum = result
|
||||
end function
|
||||
");
|
||||
Assert.AreEqual(array.Aggregate((current, next) => current + next), engine.Script.sum(array));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("VBScriptEngine")]
|
||||
public void VBScriptEngine_NativeEnumerator_Generic()
|
||||
{
|
||||
var array = Enumerable.Range(0, 10).Select(value => (IConvertible)value).ToArray();
|
||||
engine.Script.culture = CultureInfo.InvariantCulture;
|
||||
engine.Execute(@"
|
||||
function sum(array)
|
||||
dim result
|
||||
result = 0
|
||||
for each item in array
|
||||
result = result + item.ToInt32(culture)
|
||||
next
|
||||
sum = result
|
||||
end function
|
||||
");
|
||||
Assert.AreEqual(array.Aggregate((current, next) => Convert.ToInt32(current) + Convert.ToInt32(next)), engine.Script.sum(array));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("VBScriptEngine")]
|
||||
public void VBScriptEngine_NativeEnumerator_NonGeneric()
|
||||
{
|
||||
var array = Enumerable.Range(0, 10).ToArray();
|
||||
engine.Execute(@"
|
||||
function sum(array)
|
||||
dim result
|
||||
result = 0
|
||||
for each item in array
|
||||
result = result + item
|
||||
next
|
||||
sum = result
|
||||
end function
|
||||
");
|
||||
Assert.AreEqual(array.Aggregate((current, next) => current + next), engine.Script.sum(HostObject.Wrap(array, typeof(IEnumerable))));
|
||||
}
|
||||
|
||||
[TestMethod, TestCategory("VBScriptEngine")]
|
||||
public void VBScriptEngine_NativeEnumerator_NonEnumerable()
|
||||
{
|
||||
engine.Execute(@"
|
||||
function sum(array)
|
||||
dim result
|
||||
result = 0
|
||||
for each item in array
|
||||
result = result + item
|
||||
next
|
||||
sum = result
|
||||
end function
|
||||
");
|
||||
TestUtil.AssertException<NotSupportedException>(() => engine.Script.sum(DayOfWeek.Monday));
|
||||
}
|
||||
|
||||
// ReSharper restore InconsistentNaming
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -5,9 +5,9 @@ setlocal
|
|||
:: process arguments
|
||||
::-----------------------------------------------------------------------------
|
||||
|
||||
set v8testedrev=4.4.63.29
|
||||
set v8testedrev=4.7.80.25
|
||||
|
||||
set gyprev=0bb67471bca068996e15b56738fa4824dfa19de0
|
||||
set gyprev=01528c7244837168a1c80f06ff60fa5a9793c824
|
||||
set cygwinrev=c89e446b273697fadf3a10ff1007a97c0b7de6df
|
||||
|
||||
:ProcessArgs
|
||||
|
@ -167,7 +167,7 @@ cd ..\..
|
|||
|
||||
:DownloadCygwin
|
||||
echo Downloading Cygwin ...
|
||||
git clone -n -q https://chromium.googlesource.com/chromium/deps/cygwin.git third_party/cygwin
|
||||
git clone -n -q https://chromium.googlesource.com/chromium/deps/cygwin.git third_party\cygwin
|
||||
if errorlevel 1 goto Error
|
||||
cd third_party/cygwin
|
||||
git checkout -q "%cygwinrev%"
|
||||
|
@ -185,6 +185,8 @@ cd ..
|
|||
|
||||
:Build
|
||||
|
||||
set DEPOT_TOOLS_WIN_TOOLCHAIN=0
|
||||
|
||||
:CreatePatchFile
|
||||
echo Creating patch file ...
|
||||
cd v8
|
||||
|
|
|
@ -1 +1 @@
|
|||
<# var version = new Version(5, 4, 3, 0); #>
|
||||
<# var version = new Version(5, 4, 4, 0); #>
|
||||
|
|
Загрузка…
Ссылка в новой задаче