Skip to content

Commit

Permalink
Version 7.4.4: Added ConcurrentPropertyBag (GitHub Issue #531); [V8] …
Browse files Browse the repository at this point in the history
…added V8ScriptEngineFlags.UseSynchronizationContexts (GitHub Discussion #509); added ScriptEngine.CustomAttributeLoader (GitHub Discussion #540); fixed property accessor recursion bug (GitHub Issue #541); added ScriptEngine.HostData and CustomAttributeLoader.Default; updated API documentation. Tested with V8 11.8.172.15.
  • Loading branch information
ClearScriptLib committed Oct 17, 2023
1 parent cb50bb0 commit 6df5f19
Show file tree
Hide file tree
Showing 835 changed files with 2,256 additions and 1,457 deletions.
4 changes: 2 additions & 2 deletions ClearScript/CanonicalRefTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ private static ICanonicalRefMap GetMap(object obj)
type == typeof(TimeSpan) ||
type == typeof(Guid) ||
#if NET471_OR_GREATER || NETCOREAPP2_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
type.GetOrLoadCustomAttributes<System.Runtime.CompilerServices.IsReadOnlyAttribute>(false).Any() ||
type.GetOrLoadCustomAttributes<System.Runtime.CompilerServices.IsReadOnlyAttribute>(null, false).Any() ||
#endif
type.GetOrLoadCustomAttributes<ImmutableValueAttribute>(false).Any())
type.GetOrLoadCustomAttributes<ImmutableValueAttribute>(null, false).Any())
{
map = (ICanonicalRefMap)typeof(CanonicalRefMap<>).MakeGenericType(type).CreateInstance();
}
Expand Down
136 changes: 136 additions & 0 deletions ClearScript/CustomAttributeCache.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using Microsoft.ClearScript.Util;

namespace Microsoft.ClearScript
{
internal sealed class CustomAttributeCache
{
private readonly ConditionalWeakTable<ICustomAttributeProvider, Entry> table = new ConditionalWeakTable<ICustomAttributeProvider, Entry>();

public T[] GetOrLoad<T>(CustomAttributeLoader loader, ICustomAttributeProvider resource, bool inherit) where T : Attribute
{
lock (table)
{
return GetOrLoad<T>(loader, table.GetOrCreateValue(resource), resource, inherit);
}
}

private T[] GetOrLoad<T>(CustomAttributeLoader loader, Entry entry, ICustomAttributeProvider resource, bool inherit) where T : Attribute
{
if (entry.TryGet<T>(out var attrs))
{
return attrs;
}

attrs = Load<T>(GetIsBypass(entry, resource) ? CustomAttributeLoader.Default : loader, resource, inherit);
entry.Add(attrs);

return attrs;
}

private static T[] Load<T>(CustomAttributeLoader loader, ICustomAttributeProvider resource, bool inherit) where T : Attribute
{
return loader.LoadCustomAttributes<T>(resource, inherit) ?? ArrayHelpers.GetEmptyArray<T>();
}

private bool GetIsBypass(ICustomAttributeProvider resource)
{
// ReSharper disable once InconsistentlySynchronizedField
return GetIsBypass(table.GetOrCreateValue(resource), resource);
}

private bool GetIsBypass(Entry entry, ICustomAttributeProvider resource)
{
if (!entry.IsBypass.HasValue)
{
entry.IsBypass = GetIsBypassInternal(resource);
}

return entry.IsBypass.Value;
}

private bool GetIsBypassInternal(ICustomAttributeProvider resource)
{
if (Load<BypassCustomAttributeLoaderAttribute>(CustomAttributeLoader.Default, resource, false).Length > 0)
{
return true;
}

var parent = GetParent(resource);
if (parent != null)
{
return GetIsBypass(parent);
}

return false;
}

private static ICustomAttributeProvider GetParent(ICustomAttributeProvider resource)
{
if (resource is ParameterInfo parameter)
{
return parameter.Member;
}

if (resource is Type type)
{
return (type.DeclaringType as ICustomAttributeProvider) ?? type.Module;
}

if (resource is MemberInfo member)
{
return member.DeclaringType;
}

if (resource is Module module)
{
return module.Assembly;
}

return null;
}

#region Nested type: Entry

// ReSharper disable ClassNeverInstantiated.Local

private sealed class Entry
{
private readonly Dictionary<Type, object> map = new Dictionary<Type, object>();

public bool? IsBypass { get; set; }

public void Add<T>(T[] attrs)
{
map.Add(typeof(T), attrs);
}

public bool TryGet<T>(out T[] attrs)
{
if (map.TryGetValue(typeof(T), out var attrsObject))
{
attrs = attrsObject as T[];
return true;
}

attrs = null;
return false;
}
}

// ReSharper restore ClassNeverInstantiated.Local

#endregion
}

[AttributeUsage(AttributeTargets.All, Inherited = false)]
internal sealed class BypassCustomAttributeLoaderAttribute : Attribute
{
}
}
12 changes: 12 additions & 0 deletions ClearScript/CustomAttributeLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ namespace Microsoft.ClearScript
/// </summary>
public class CustomAttributeLoader
{
private readonly CustomAttributeCache cache = new CustomAttributeCache();

// ReSharper disable EmptyConstructor

/// <summary>
Expand All @@ -22,6 +24,11 @@ public CustomAttributeLoader()
// the help file builder (SHFB) insists on an empty constructor here
}

/// <summary>
/// Gets the default custom attribute loader.
/// </summary>
public static CustomAttributeLoader Default { get; } = new CustomAttributeLoader();

// ReSharper restore EmptyConstructor

/// <summary>
Expand Down Expand Up @@ -60,5 +67,10 @@ public virtual T[] LoadCustomAttributes<T>(ICustomAttributeProvider resource, bo

return resource.GetCustomAttributes(typeof(T), inherit).OfType<T>().ToArray();
}

internal T[] GetOrLoad<T>(ICustomAttributeProvider resource, bool inherit) where T : Attribute
{
return cache.GetOrLoad<T>(this, resource, inherit);
}
}
}
21 changes: 0 additions & 21 deletions ClearScript/CustomAttributes.NetFramework.cs

This file was deleted.

21 changes: 0 additions & 21 deletions ClearScript/CustomAttributes.NetStandard.cs

This file was deleted.

145 changes: 7 additions & 138 deletions ClearScript/CustomAttributes.cs
Original file line number Diff line number Diff line change
@@ -1,154 +1,23 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.ClearScript.Util;

namespace Microsoft.ClearScript
{
internal static partial class CustomAttributes
internal static class CustomAttributes
{
private static readonly object cacheLock = new object();

public static T[] GetOrLoad<T>(ICustomAttributeProvider resource, bool inherit) where T : Attribute
{
lock (cacheLock)
{
return GetOrLoad<T>(cache.GetOrCreateValue(resource), resource, inherit);
}
}

public static bool Has<T>(ICustomAttributeProvider resource, bool inherit) where T : Attribute
{
lock (cacheLock)
{
return Has<T>(cache.GetOrCreateValue(resource), resource, inherit);
}
}

private static T[] GetOrLoad<T>(CacheEntry entry, ICustomAttributeProvider resource, bool inherit) where T : Attribute
{
if (entry.TryGet<T>(out var attrs))
{
return attrs;
}

attrs = GetOrLoad<T>(GetIsBypass(entry, resource), resource, inherit);
entry.Add(attrs);

return attrs;
}

private static bool Has<T>(CacheEntry entry, ICustomAttributeProvider resource, bool inherit) where T : Attribute
{
return GetOrLoad<T>(entry, resource, inherit).Length > 0;
}

private static T[] GetOrLoad<T>(bool isBypass, ICustomAttributeProvider resource, bool inherit) where T : Attribute
{
var loader = isBypass ? HostSettings.DefaultCustomAttributeLoader : HostSettings.CustomAttributeLoader;
return loader.LoadCustomAttributes<T>(resource, inherit) ?? ArrayHelpers.GetEmptyArray<T>();
}

private static bool Has<T>(bool isBypass, ICustomAttributeProvider resource, bool inherit) where T : Attribute
{
return GetOrLoad<T>(isBypass, resource, inherit).Length > 0;
}

private static bool GetIsBypass(ICustomAttributeProvider resource)
{
// ReSharper disable once InconsistentlySynchronizedField
return GetIsBypass(cache.GetOrCreateValue(resource), resource);
}

private static bool GetIsBypass(CacheEntry entry, ICustomAttributeProvider resource)
public static T[] GetOrLoad<T>(IHostContext context, ICustomAttributeProvider resource, bool inherit) where T : Attribute
{
if (!entry.IsBypass.HasValue)
{
entry.IsBypass = GetIsBypassInternal(resource);
}

return entry.IsBypass.Value;
}

private static bool GetIsBypassInternal(ICustomAttributeProvider resource)
{
if (Has<BypassCustomAttributeLoaderAttribute>(true, resource, false))
{
return true;
}

var parent = GetParent(resource);
if (parent != null)
{
return GetIsBypass(parent);
}

return false;
}

private static ICustomAttributeProvider GetParent(ICustomAttributeProvider resource)
{
if (resource is ParameterInfo parameter)
{
return parameter.Member;
}

if (resource is Type type)
{
return (type.DeclaringType as ICustomAttributeProvider) ?? type.Module;
}

if (resource is MemberInfo member)
{
return member.DeclaringType;
}

if (resource is Module module)
{
return module.Assembly;
}

return null;
var loader = context?.CustomAttributeLoader ?? HostSettings.CustomAttributeLoader;
return loader.GetOrLoad<T>(resource, inherit);
}

#region Nested type: CacheEntry

// ReSharper disable ClassNeverInstantiated.Local

private sealed class CacheEntry
public static bool Has<T>(IHostContext context, ICustomAttributeProvider resource, bool inherit) where T : Attribute
{
private readonly Dictionary<Type, object> map = new Dictionary<Type, object>();

public bool? IsBypass { get; set; }

public void Add<T>(T[] attrs)
{
map.Add(typeof(T), attrs);
}

public bool TryGet<T>(out T[] attrs)
{
if (map.TryGetValue(typeof(T), out var attrsObject))
{
attrs = attrsObject as T[];
return true;
}

attrs = null;
return false;
}
return GetOrLoad<T>(context, resource, inherit).Length > 0;
}

// ReSharper restore ClassNeverInstantiated.Local

#endregion
}

[AttributeUsage(AttributeTargets.All, Inherited = false)]
internal sealed class BypassCustomAttributeLoaderAttribute : Attribute
{
}
}
6 changes: 3 additions & 3 deletions ClearScript/Exports/VersionSymbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

#pragma once

#define CLEARSCRIPT_VERSION_STRING "7.4.3"
#define CLEARSCRIPT_VERSION_COMMA_SEPARATED 7,4,3
#define CLEARSCRIPT_VERSION_STRING_INFORMATIONAL "7.4.3"
#define CLEARSCRIPT_VERSION_STRING "7.4.4"
#define CLEARSCRIPT_VERSION_COMMA_SEPARATED 7,4,4
#define CLEARSCRIPT_VERSION_STRING_INFORMATIONAL "7.4.4"
#define CLEARSCRIPT_FILE_FLAGS 0L
Loading

0 comments on commit 6df5f19

Please sign in to comment.