Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Non-allocating fast path for compiling code #615

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 44 additions & 8 deletions ClearScript/Util/MiscHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,17 +224,36 @@ public static UIntPtr GetDigest(this string code)
return (UIntPtr.Size == 4) ? (UIntPtr)code.GetDigestAsUInt32() : (UIntPtr)code.GetDigestAsUInt64();
}

public static UIntPtr GetDigest(IntPtr code, int length)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to use Span<byte>, but it is not available in .NET 4.5.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ClearScript 7.5 will use Span, at least internally. To do that on .NET Framework 4.5, it'll bring in System.Memory 4.5.5.

{
return (UIntPtr.Size == 4) ? (UIntPtr)GetDigestAsUInt32(code, length) : (UIntPtr)GetDigestAsUInt64(code, length);
}

public static uint GetDigestAsUInt32(this string code)
{
unsafe
{
fixed (char* charPtr = code)
{
return GetDigestAsUInt32((IntPtr)charPtr, code.Length);
}
}
}

/// <param name="code">A pointer to a UTF-16 string</param>
/// <param name="length">The length of the code string</param>
public static uint GetDigestAsUInt32(IntPtr code, int length)
{
var digest = 2166136261U;
const uint prime = 16777619U;

unchecked
unsafe
{
var bytes = Encoding.Unicode.GetBytes(code);
for (var index = 0; index < bytes.Length; index++)
byte* bytePtr = (byte*)code;

for (var index = 0; index < length; index++)
{
digest ^= bytes[index];
digest ^= bytePtr[index];
digest *= prime;
}
}
Expand All @@ -243,15 +262,32 @@ public static uint GetDigestAsUInt32(this string code)
}

public static ulong GetDigestAsUInt64(this string code)
{
unsafe
{
fixed (char* charPtr = code)
{
return GetDigestAsUInt64((IntPtr)charPtr, code.Length);
}
}
}

/// <param name="code">A pointer to a UTF-16 string</param>
/// <param name="length">The length of the code string</param>
public static ulong GetDigestAsUInt64(IntPtr code, int length)
{
var digest = 14695981039346656037UL;
const ulong prime = 1099511628211UL;

var bytes = Encoding.Unicode.GetBytes(code);
for (var index = 0; index < bytes.Length; index++)
unsafe
{
digest ^= bytes[index];
digest *= prime;
byte* bytePtr = (byte*)code;

for (var index = 0; index < length; index++)
{
digest ^= bytePtr[index];
digest *= prime;
}
}

return digest;
Expand Down
1 change: 1 addition & 0 deletions ClearScript/V8/SplitProxy/IV8SplitProxyNative.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ internal interface IV8SplitProxyNative
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);
V8Script.Handle V8Context_Compile(V8Context.Handle hContext, string resourceName, string sourceMapUrl, ulong uniqueId, DocumentKind documentKind, IntPtr pDocumentInfo, string code);
V8Script.Handle V8Context_Compile(V8Context.Handle hContext, string resourceName, string sourceMapUrl, ulong uniqueId, DocumentKind documentKind, IntPtr pDocumentInfo, IntPtr code, int length);
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);
V8Script.Handle V8Context_CompileUpdatingCache(V8Context.Handle hContext, string resourceName, string sourceMapUrl, ulong uniqueId, DocumentKind documentKind, IntPtr pDocumentInfo, string code, V8CacheKind cacheKind, ref byte[] cacheBytes, out V8CacheResult cacheResult);
Expand Down
16 changes: 16 additions & 0 deletions ClearScript/V8/SplitProxy/V8ContextProxyImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,22 @@ public override V8.V8Script Compile(UniqueDocumentInfo documentInfo, string code
V8ProxyHelpers.AddRefHostObject(documentInfo),
code
)));
}

/// <param name="documentInfo">Meta-information for a document</param>
/// <param name="code">A pointer to a UTF-16 string</param>
/// <param name="length">The length of the code string</param>
public override V8.V8Script Compile(UniqueDocumentInfo documentInfo, IntPtr code, int length)
{
return new V8ScriptImpl(documentInfo, MiscHelpers.GetDigest(code, length), V8SplitProxyNative.Invoke(instance => instance.V8Context_Compile(
Handle,
MiscHelpers.GetUrlOrPath(documentInfo.Uri, documentInfo.UniqueName),
MiscHelpers.GetUrlOrPath(documentInfo.SourceMapUri, string.Empty),
documentInfo.UniqueId,
documentInfo.Category.Kind,
V8ProxyHelpers.AddRefHostObject(documentInfo),
code, length
)));
}

public override V8.V8Script Compile(UniqueDocumentInfo documentInfo, string code, V8CacheKind cacheKind, out byte[] cacheBytes)
Expand Down
22 changes: 22 additions & 0 deletions ClearScript/V8/SplitProxy/V8SplitProxyNative.Common.tt
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,17 @@ namespace Microsoft.ClearScript.V8.SplitProxy
}
}

V8Script.Handle IV8SplitProxyNative.V8Context_Compile(V8Context.Handle hContext, string resourceName, string sourceMapUrl, ulong uniqueId, DocumentKind documentKind, IntPtr pDocumentInfo, IntPtr code, int length)
{
using (var resourceNameScope = StdString.CreateScope(resourceName))
{
using (var sourceMapUrlScope = StdString.CreateScope(sourceMapUrl))
{
return V8Context_CompileIntPtr(hContext, resourceNameScope.Value, sourceMapUrlScope.Value, uniqueId, documentKind, pDocumentInfo, code, length);
}
}
}

V8Script.Handle IV8SplitProxyNative.V8Context_CompileProducingCache(V8Context.Handle hContext, string resourceName, string sourceMapUrl, ulong uniqueId, DocumentKind documentKind, IntPtr pDocumentInfo, string code, V8CacheKind cacheKind, out byte[] cacheBytes)
{
using (var resourceNameScope = StdString.CreateScope(resourceName))
Expand Down Expand Up @@ -1848,6 +1859,17 @@ namespace Microsoft.ClearScript.V8.SplitProxy
[In] StdString.Ptr pCode
);

[DllImport("<#= fileName #>", CallingConvention = CallingConvention.StdCall)]
private static extern V8Script.Handle V8Context_CompileIntPtr(
[In] V8Context.Handle hContext,
[In] StdString.Ptr pResourceName,
[In] StdString.Ptr pSourceMapUrl,
[In] ulong uniqueId,
[In] DocumentKind documentKind,
[In] IntPtr pDocumentInfo,
[In] IntPtr pCode, [In] int length
);

[DllImport("<#= fileName #>", CallingConvention = CallingConvention.StdCall)]
private static extern V8Script.Handle V8Context_CompileProducingCache(
[In] V8Context.Handle hContext,
Expand Down
Loading