Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
484784c
Add PInvoke attribute to enabled Marshalling in Unity
mikhail-dcl Apr 11, 2023
6967520
Merge branch 'microsoft:master' into master
mikhail-dcl May 10, 2023
7113526
Optimize Reflection Hot Paths
mikhail-dcl May 12, 2023
87e7fc7
Merge branch 'microsoft:master' into master
mikhail-dcl Jun 9, 2023
a5ea288
Add HasFlag non-alloc
mikhail-dcl Jun 9, 2023
18ab651
Merge remote-tracking branch 'origin/master'
mikhail-dcl Jun 9, 2023
eb896d2
Restore `Create`
mikhail-dcl Jun 9, 2023
49a4728
Merge branch 'master' of github.com:microsoft/ClearScript into micros…
AnsisMalins Jan 21, 2025
e6002ba
Fix compiler errors and remove TypesCache
AnsisMalins Jan 21, 2025
aa2e2e6
Remove MonoPInvokeCallbackAttribute
AnsisMalins Jan 21, 2025
6ea8a82
Merge pull request #2 from decentraland/microsoft-master
AnsisMalins Jan 22, 2025
2af16db
Fix T4 generating files with mixed line endings
AnsisMalins Jan 23, 2025
71b9494
Add an unsafe low level API for V8
AnsisMalins Jan 23, 2025
f50538a
Add code paths for the new API
AnsisMalins Jan 24, 2025
ac0b77b
Create a Unity package
AnsisMalins Jan 24, 2025
1378a64
Merge pull request #3 from decentraland/fix/t4-newlines
mikhail-dcl Jan 27, 2025
080731a
Merge pull request #4 from decentraland/feat/unsafe-v8-api
AnsisMalins Jan 28, 2025
5cd2bf6
Merge branch 'master' into feat/unity-package
AnsisMalins Jan 28, 2025
7fa87eb
Merge pull request #5 from decentraland/feat/unity-package
AnsisMalins Jan 28, 2025
ee536bf
Update the Unity package
AnsisMalins Jan 28, 2025
6853a77
Merge pull request #6 from decentraland/fix/fixup-unity-package
AnsisMalins Jan 29, 2025
0b03183
compiled binaries
NickKhalow Jan 29, 2025
082796d
add meta files
NickKhalow Jan 29, 2025
ebbf2b5
Merge pull request #7 from decentraland/compile-macos
AnsisMalins Jan 29, 2025
8263f3a
Add MonoPInvokeCallback attributes for IL2CPP
AnsisMalins Jan 29, 2025
af9ada5
Fix Unity crashes
AnsisMalins Jan 30, 2025
1cea390
Temporary debug code slipped in
AnsisMalins Jan 30, 2025
4e93124
Merge pull request #9 from decentraland/fix/fix-crashes
AnsisMalins Jan 30, 2025
985bb78
Switch to Release builds of libraries
AnsisMalins Jan 30, 2025
1cd1472
Mandatory XML comment
AnsisMalins Jan 30, 2025
32e46bc
Merge pull request #8 from decentraland/fix/il2cpp-compatibility
mikhail-dcl Jan 31, 2025
6eb74e0
Add unit tests covering some of IV8ScriptableObject
AnsisMalins Feb 4, 2025
1b07462
Use asserts better
AnsisMalins Feb 4, 2025
5a1a562
Merge pull request #10 from decentraland/chore/unit-tests-iv8scriptab…
AnsisMalins Feb 4, 2025
e73c03b
Remove V8Function class
AnsisMalins Feb 4, 2025
99f9516
Fix line endings and whitespace
AnsisMalins Feb 6, 2025
fcfd8a3
More unit tests
AnsisMalins Feb 6, 2025
ae33230
Fixed a Visual Studio warning
AnsisMalins Feb 6, 2025
b9cdcdc
Merge pull request #12 from decentraland/chore/fix-line-endings
AnsisMalins Feb 6, 2025
284f253
Merge branch 'master' into chore/remove-v8function
AnsisMalins Feb 6, 2025
4d4e72a
Merge pull request #11 from decentraland/chore/remove-v8function
AnsisMalins Feb 6, 2025
035af65
Merge branch 'master' into chore/more-unit-tests
AnsisMalins Feb 6, 2025
f923816
Merge pull request #13 from decentraland/chore/more-unit-tests
AnsisMalins Feb 6, 2025
868b215
Changes to support changes to CommunicationsControllerAPIWrapper
AnsisMalins Feb 6, 2025
15654a0
Add Linux x64 binary
AnsisMalins Feb 10, 2025
4950c75
Merge pull request #15 from decentraland/feat/linux-x64-binary
AnsisMalins Feb 10, 2025
2a02b6b
Set OS/CPU combos for the native libraries
AnsisMalins Feb 10, 2025
83dd9e2
Constrain the test assembly to tests
AnsisMalins Feb 10, 2025
ca807a7
Merge pull request #14 from decentraland/feat/indexedproperty
AnsisMalins Feb 11, 2025
1a5006f
More unit tests and error checking
AnsisMalins Feb 12, 2025
2e0eb7c
Merge pull request #16 from decentraland/chore/more-unit-tests-2
AnsisMalins Feb 13, 2025
93a5e34
Add convenience getters to V8Value
AnsisMalins Feb 13, 2025
60d6bf0
Merge pull request #17 from decentraland/feat/get-value-convenience
AnsisMalins Feb 13, 2025
a294994
Get ClearScript to compile on Visual Studio 17.13
AnsisMalins Feb 14, 2025
7831a24
Add timeouts to stalling JScript tests
AnsisMalins Feb 14, 2025
9bf9ee3
Change invoke to a using struct
AnsisMalins Feb 14, 2025
e14e535
Fix WriteBytesToStream on .NET Framework
AnsisMalins Feb 19, 2025
2846699
Do the right thing in face of exceptions
AnsisMalins Feb 19, 2025
5b37e54
Merge pull request #18 from decentraland/feat/using-invoke-scope
AnsisMalins Feb 20, 2025
4d02af4
Update the Unity package
AnsisMalins Feb 20, 2025
0ddb18f
fix: remove linq call in InvokeMethod
mihakrajnc Aug 28, 2025
acd1e2d
enable package
m3taphysics Sep 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
677 changes: 343 additions & 334 deletions ClearScript.sln

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions ClearScript/DelegateFactory.tt
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ namespace Microsoft.ClearScript
var allByValueExpr = (count == 0) ? "true" : "GetAllByValue(" + string.Join(", ", Enumerable.Range(1, count).Select(index => "typeof(T" + index + ")")) + ")";
var methodParamList = string.Join(", ", Enumerable.Range(1, count).Select(index => "T" + index + " a" + index));
var argList = string.Join(", ", Enumerable.Range(1, count).Select(index => "a" + index));
var varDeclList = string.Join("\r\n ", Enumerable.Range(1, count).Select(index => "var v" + index + " = GetArgValue(a" + index + ");"));
var varDeclList = string.Join("\n ", Enumerable.Range(1, count).Select(index => "var v" + index + " = GetArgValue(a" + index + ");"));
var byRefArgList = string.Join(", ", Enumerable.Range(1, count).Select(index => "ref v" + index));
var varAssignList = string.Join("\r\n ", Enumerable.Range(1, count).Select(index => "SetArgValue(a" + index + ", v" + index + ");"));
var varAssignList = string.Join("\n ", Enumerable.Range(1, count).Select(index => "SetArgValue(a" + index + ", v" + index + ");"));
#>

[ExcludeFromCodeCoverage]
Expand Down Expand Up @@ -97,9 +97,9 @@ namespace Microsoft.ClearScript
var allByValueExpr = (count == 0) ? "true" : "GetAllByValue(" + string.Join(", ", Enumerable.Range(1, count).Select(index => "typeof(T" + index + ")")) + ")";
var methodParamList = string.Join(", ", Enumerable.Range(1, count).Select(index => "T" + index + " a" + index));
var argList = string.Join(", ", Enumerable.Range(1, count).Select(index => "a" + index));
var varDeclList = string.Join("\r\n ", Enumerable.Range(1, count).Select(index => "var v" + index + " = GetArgValue(a" + index + ");"));
var varDeclList = string.Join("\n ", Enumerable.Range(1, count).Select(index => "var v" + index + " = GetArgValue(a" + index + ");"));
var byRefArgList = string.Join(", ", Enumerable.Range(1, count).Select(index => "ref v" + index));
var varAssignList = string.Join("\r\n ", Enumerable.Range(1, count).Select(index => "SetArgValue(a" + index + ", v" + index + ");"));
var varAssignList = string.Join("\n ", Enumerable.Range(1, count).Select(index => "SetArgValue(a" + index + ", v" + index + ");"));
#>

[ExcludeFromCodeCoverage]
Expand Down
30 changes: 20 additions & 10 deletions ClearScript/HostItem.InvokeMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -497,16 +497,26 @@ public bool IsUnblockedMethod(HostItem hostItem)
return IsSuccess && !method.IsBlockedFromScript(hostItem, hostItem.DefaultAccess);
}

public object Invoke(HostItem hostItem)
{
if (!IsSuccess)
{
throw exceptionFactory();
}

if (reflectionMethods.Contains(method, MemberComparer<MethodInfo>.Instance))
{
hostItem.Engine.CheckReflection();
public object Invoke(HostItem hostItem)
{
if (!IsSuccess)
{
throw exceptionFactory();
}

bool isReflectionMethod = false;
for (int i = 0; i < reflectionMethods.Length; i++)
{
if (MemberComparer<MethodInfo>.Instance.Equals(reflectionMethods[i], method))
{
isReflectionMethod = true;
break;
}
}

if (isReflectionMethod)
{
hostItem.Engine.CheckReflection();
}

return InvokeHelpers.InvokeMethod(hostItem, method, hostTarget.InvokeTarget, args, method.GetScriptMemberFlags(hostItem));
Expand Down
81 changes: 42 additions & 39 deletions ClearScript/HostItem.cs

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions ClearScript/Properties/AssemblyInfo.V8.ICUData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@











using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
Expand All @@ -13,6 +21,7 @@
[assembly: AssemblyProduct("ClearScript")]
[assembly: AssemblyCopyright("(c) Microsoft Corporation")]
[assembly: InternalsVisibleTo("ClearScript.V8")]
[assembly: InternalsVisibleTo("Decentraland.ClearScript")]

[assembly: ComVisible(false)]
[assembly: AssemblyVersion("7.4.5")]
Expand Down
1 change: 1 addition & 0 deletions ClearScript/Properties/AssemblyInfo.V8.ICUData.tt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyProduct("ClearScript")]
[assembly: AssemblyCopyright("(c) Microsoft Corporation")]
[assembly: InternalsVisibleTo("<#= "ClearScript.V8" + publicKeySpec #>")]
[assembly: InternalsVisibleTo("Decentraland.ClearScript")]

[assembly: ComVisible(false)]
[assembly: AssemblyVersion("<#= version.ToString(3) #>")]
Expand Down
25 changes: 25 additions & 0 deletions ClearScript/Util/EnumUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;

internal static class EnumUtils
{
public static unsafe bool HasFlagNonAlloc<T>(this T x, T y) where T : unmanaged, Enum
{
switch (sizeof(T))
{
case sizeof(byte):
return (*(byte*) &x & *(byte*) &y) != 0;

case sizeof(short):
return (*(short*) &x & *(short*) &y) != 0;

case sizeof(int):
return (*(int*) &x & *(int*) &y) != 0;

case sizeof(long):
return (*(long*) &x & *(long*) &y) != 0L;

default:
return false;
}
}
}
6 changes: 5 additions & 1 deletion ClearScript/Util/ObjectHelpers.Common.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ internal static partial class ObjectHelpers
{
private static bool GetPrimaryInteropAssembly(Guid libid, int major, int minor, out string name, out string codeBase)
{
#if UNITY_5_3_OR_NEWER // There is no just "is Unity" symbol.
throw new NotSupportedException("What the hell are you doing with COM in a Unity game??");
#else
name = null;
codeBase = null;

Expand All @@ -37,7 +40,8 @@ private static bool GetPrimaryInteropAssembly(Guid libid, int major, int minor,
}
}

return name != null;
return name != null;
#endif
}
}
}
116 changes: 116 additions & 0 deletions ClearScript/V8/SplitProxy/IV8HostObject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
using System;

namespace Microsoft.ClearScript.V8.SplitProxy
{
/// <summary>
/// Implement this interface to talk to ClearScript's native wrapper around V8 directly.
/// </summary>
public interface IV8HostObject
{
/// <summary>
/// Implement this to support getting the values of named properties.
/// </summary>
/// <param name="name">The name of the property JavaScript wants the value of.</param>
/// <param name="value">Write the value of the property here.</param>
/// <param name="isConst">If you set this to to true, V8 will cache the value not ask for it
/// again.</param>
void GetNamedProperty(StdString name, V8Value value, out bool isConst) =>
throw new NotImplementedException($"Named property {name.ToString()} is not implemented");

/// <summary>
/// Implement this to support setting the values of named properties.
/// </summary>
/// <param name="name">The name of the property JavaScript wants to set.</param>
/// <param name="value">The value JavaScript wants to set the property to.</param>
void SetNamedProperty(StdString name, V8Value.Decoded value) =>
throw new NotImplementedException($"Named property {name.ToString()} is not implemented");

/// <summary>
/// Implement this to support deleting named properties.
/// </summary>
/// <param name="name">The name of the property JavaScript wants to delete.</param>
/// <returns>TODO</returns>
bool DeleteNamedProperty(StdString name) =>
throw new NotImplementedException($"Named property {name.ToString()} is not implemented");

/// <summary>
/// Implement this to support getting the values of indexed properties.
/// </summary>
/// <param name="index">The index of the property JavaScript wants the value of.</param>
/// <param name="value">Write the value of the property here.</param>
void GetIndexedProperty(int index, V8Value value) =>
throw new NotImplementedException($"Indexed property {index} is not implemented");

/// <summary>
/// Implement this to support setting the values of indexed properties.
/// </summary>
/// <param name="index">The index of the property JavaScript wants to set.</param>
/// <param name="value">The value JavaScript wants to set the property to.</param>
void SetIndexedProperty(int index, V8Value.Decoded value) =>
throw new NotImplementedException($"Indexed property {index} is not implemented");

/// <summary>
/// Implement this to support deleting indexed properties.
/// </summary>
/// <param name="index">The index of the property JavaScript wants to delete.</param>
/// <returns>TODO</returns>
bool DeleteIndexedProperty(int index) =>
throw new NotImplementedException($"Indexed property {index} is not implemented");

/// <summary>
/// Implement this to support being enumerated.
/// </summary>
/// <param name="result">Write the enumerator here.</param>
/// <remarks>
/// The enumerator class should implement <see cref="IV8HostObject"/> and implement MoveNext(),
/// ScriptableDispose(), and CurrentValue.
/// </remarks>
void GetEnumerator(V8Value result) =>
throw new NotImplementedException("Enumerator is not implemented");

/// <summary>
/// Implement this to support being async enumerated.
/// </summary>
/// <param name="result">Write the async enumerator here.</param>
void GetAsyncEnumerator(V8Value result) =>
throw new NotImplementedException("Async enumerator is not implemented");

/// <summary>
/// Implement this to support listing of all your named proeprties.
/// </summary>
/// <param name="names">Write the names of your properties here.</param>
void GetNamedPropertyNames(StdStringArray names) =>
throw new NotImplementedException("Listing named properties is not implemented");

/// <summary>
/// Implement this to support listing all your indexed properties.
/// </summary>
/// <param name="indices">Write the indices of your properties here.</param>
void GetIndexedPropertyIndices(StdInt32Array indices) =>
throw new NotImplementedException("Listing indexed properties is not implemented");

/// <summary>
/// I don't know when ClearScript calls this.
/// </summary>
/// <param name="name">The name of the method JavaScript wants to invoke.</param>
/// <param name="args">The arguments JavaScript is passing to the method.</param>
/// <param name="result">Write the return value, if not <see cref="void"/>, of the method here.
/// </param>
void InvokeMethod(StdString name, ReadOnlySpan<V8Value.Decoded> args, V8Value result)
{
GetNamedProperty(name, result, out _);
object method = result.Decode().GetHostObject();
result.SetNonexistent();
((InvokeHostObject)method)(args, result);
}
}

/// <summary>
/// Return a delegate of this type from a property to tell JavaScript that it is a callable
/// function.
/// </summary>
/// <param name="args">The arguments JavaScript will pass to your method when invoking it.</param>
/// <param name="result">Write the return value, if not <see cref="void"/>, of the method here.
/// </param>
public delegate void InvokeHostObject(ReadOnlySpan<V8Value.Decoded> args, V8Value result);
}
6 changes: 6 additions & 0 deletions ClearScript/V8/SplitProxy/IV8SplitProxyNative.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ internal interface IV8SplitProxyNative

StdString.Ptr StdString_New(string value);
string StdString_GetValue(StdString.Ptr pString);
void StdString_GetValue(StdString.Ptr pString, out IntPtr value, out int length);
void StdString_SetValue(StdString.Ptr pString, string value);
void StdString_Delete(StdString.Ptr pString);

Expand Down Expand Up @@ -171,6 +172,7 @@ internal interface IV8SplitProxyNative
void V8Context_AwaitDebuggerAndPause(V8Context.Handle hContext);
void V8Context_CancelAwaitDebugger(V8Context.Handle hContext);
object V8Context_ExecuteCode(V8Context.Handle hContext, string resourceName, string sourceMapUrl, ulong uniqueId, DocumentKind documentKind, IntPtr pDocumentInfo, string code, bool evaluate);
void V8Context_ExecuteCode(V8Context.Handle hContext, StdString.Ptr pResourceName, StdString.Ptr pSourceMapUrl, ulong uniquId, DocumentKind documentKind, IntPtr pDocumentInfo, StdString.Ptr pCode, bool evaluate, V8Value.Ptr pResult);
V8Script.Handle V8Context_Compile(V8Context.Handle hContext, string resourceName, string sourceMapUrl, ulong uniqueId, DocumentKind documentKind, IntPtr pDocumentInfo, string code);
V8Script.Handle V8Context_CompileProducingCache(V8Context.Handle hContext, string resourceName, string sourceMapUrl, ulong uniqueId, DocumentKind documentKind, IntPtr pDocumentInfo, string code, V8CacheKind cacheKind, out byte[] cacheBytes);
V8Script.Handle V8Context_CompileConsumingCache(V8Context.Handle hContext, string resourceName, string sourceMapUrl, ulong uniqueId, DocumentKind documentKind, IntPtr pDocumentInfo, string code, V8CacheKind cacheKind, byte[] cacheBytes, out bool cacheAccepted);
Expand Down Expand Up @@ -199,17 +201,21 @@ internal interface IV8SplitProxyNative
#region V8 object methods

object V8Object_GetNamedProperty(V8Object.Handle hObject, string name);
void V8Object_GetNamedProperty(V8Object.Handle hObject, StdString.Ptr pName, V8Value.Ptr pValue);
bool V8Object_TryGetNamedProperty(V8Object.Handle hObject, string name, out object value);
void V8Object_SetNamedProperty(V8Object.Handle hObject, string name, object value);
bool V8Object_DeleteNamedProperty(V8Object.Handle hObject, string name);
string[] V8Object_GetPropertyNames(V8Object.Handle hObject, bool includeIndices);
object V8Object_GetIndexedProperty(V8Object.Handle hObject, int index);
void V8Object_GetIndexedProperty(V8Object.Handle hObject, int index, V8Value.Ptr pValue);
void V8Object_SetIndexedProperty(V8Object.Handle hObject, int index, object value);
bool V8Object_DeleteIndexedProperty(V8Object.Handle hObject, int index);
int[] V8Object_GetPropertyIndices(V8Object.Handle hObject);
object V8Object_Invoke(V8Object.Handle hObject, bool asConstructor, object[] args);
void V8Object_Invoke(V8Object.Handle hObject, bool asConstructor, StdV8ValueArray.Ptr pArgs, V8Value.Ptr pResult);
object V8Object_InvokeMethod(V8Object.Handle hObject, string name, object[] args);
void V8Object_GetArrayBufferOrViewInfo(V8Object.Handle hObject, out IV8Object arrayBuffer, out ulong offset, out ulong size, out ulong length);
void V8Object_GetArrayBufferOrViewInfo(V8Object.Handle hObject, V8Value.Ptr pArrayBuffer, out ulong offset, out ulong size, out ulong length);
void V8Object_InvokeWithArrayBufferOrViewData(V8Object.Handle hObject, IntPtr pAction);

#endregion
Expand Down
7 changes: 5 additions & 2 deletions ClearScript/V8/SplitProxy/NativeCallbackImpl.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

using System;
Expand All @@ -21,7 +21,10 @@ public NativeCallbackImpl(NativeCallback.Handle hCallback)

public void Invoke()
{
V8SplitProxyNative.InvokeNoThrow(instance => instance.NativeCallback_Invoke(Handle));
using (V8SplitProxyNative.InvokeNoThrow(out var instance))
{
instance.NativeCallback_Invoke(Handle);
}
}

#endregion
Expand Down
56 changes: 56 additions & 0 deletions ClearScript/V8/SplitProxy/Uint8Array.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System;
using System.Runtime.InteropServices;

namespace Microsoft.ClearScript.V8.SplitProxy
{
/// <summary>
/// Wraps a Uint8Array, an array of <see cref="byte"/>.
/// </summary>
public readonly ref struct Uint8Array
{
private readonly V8Object.Handle ptr;

internal Uint8Array(V8Object.Handle pArray)
{
ptr = pArray;
using var arrayBuffer = V8Value.New();

V8SplitProxyNative.Instance.V8Object_GetArrayBufferOrViewInfo(pArray, arrayBuffer.ptr,
out _, out _, out ulong length);

Length = (int)length;
}

/// <summary>
/// Copy the contents of the wrapped Uint8Array to a managed <see cref="byte"/> array.
/// </summary>
/// <param name="array">The destination array. It must be large enough to contain the entire
/// contents of the wrapped Uint8Array.</param>
public void CopyTo(byte[] array)
{
int length = Length;

if (length > array.Length)
throw new IndexOutOfRangeException(
$"Tried to copy {length} items to a {array.Length} item array");

// TODO: Don't allocate a lambda every time.
IntPtr pAction = V8ProxyHelpers.AddRefHostObject(new Action<IntPtr>(data =>
Marshal.Copy(data, array, 0, length)));

try
{
V8SplitProxyNative.Instance.V8Object_InvokeWithArrayBufferOrViewData(ptr, pAction);
}
finally
{
V8ProxyHelpers.ReleaseHostObject(pAction);
}
}

/// <summary>
/// The length of the wrapped Uint8Array.
/// </summary>
public int Length { get; }
}
}
Loading