Skip to content

Commit bc70fda

Browse files
Added V8ScriptEngine.SuppressExtensionMethodEnumeration.
1 parent e3f641f commit bc70fda

17 files changed

+132
-22
lines changed

ClearScript/ExtensionMethods.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,18 @@ public bool ProcessType(Type type, ScriptAccess defaultAccess)
8686
{
8787
const BindingFlags bindFlags = BindingFlags.Public | BindingFlags.Static;
8888
table[type] = type.GetMethods(bindFlags).Where(method => IsScriptableExtensionMethod(method, defaultAccess)).ToArray();
89-
summary = new ExtensionMethodSummary(table);
89+
RebuildSummary();
9090
return true;
9191
}
9292

9393
return false;
9494
}
9595

96+
public void RebuildSummary()
97+
{
98+
summary = new ExtensionMethodSummary(table);
99+
}
100+
96101
private static bool IsScriptableExtensionMethod(MethodInfo method, ScriptAccess defaultAccess)
97102
{
98103
return method.IsScriptable(defaultAccess) && method.IsDefined(typeof(ExtensionAttribute), false);

ClearScript/HostItem.cs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,17 @@ private string[] AllMethodNames
378378
set { targetMemberData.AllMethodNames = value; }
379379
}
380380

381+
private string[] OwnMethodNames
382+
{
383+
get { return targetMemberData.OwnMethodNames; }
384+
set { targetMemberData.OwnMethodNames = value; }
385+
}
386+
387+
private string[] EnumeratedMethodNames
388+
{
389+
get { return engine.EnumerateExtensionMethods ? AllMethodNames : OwnMethodNames; }
390+
}
391+
381392
private string[] AllPropertyNames
382393
{
383394
get { return targetMemberData.AllPropertyNames; }
@@ -654,20 +665,35 @@ private string[] GetAllFieldNames()
654665
return MiscHelpers.GetEmptyArray<string>();
655666
}
656667

657-
private string[] GetAllMethodNames()
668+
private string[] GetAllMethodNames(out string[] ownMethodNames)
658669
{
670+
ownMethodNames = null;
671+
659672
var names = target.GetAuxMethodNames(this, GetMethodBindFlags()).AsEnumerable();
660673
if ((TargetDynamic == null) && (TargetPropertyBag == null))
661674
{
662675
names = names.Concat(GetLocalMethodNames());
663676
if (target.Flags.HasFlag(HostTargetFlags.AllowExtensionMethods))
664677
{
665-
ExtensionMethodSummary = engine.ExtensionMethodSummary;
666-
names = names.Concat(ExtensionMethodSummary.MethodNames);
678+
var extensionMethodSummary = engine.ExtensionMethodSummary;
679+
ExtensionMethodSummary = extensionMethodSummary;
680+
681+
var extensionMethodNames = extensionMethodSummary.MethodNames;
682+
if (extensionMethodNames.Length > 0)
683+
{
684+
ownMethodNames = names.Distinct().ToArray();
685+
names = ownMethodNames.Concat(extensionMethodNames);
686+
}
667687
}
668688
}
669689

670-
return names.Distinct().ToArray();
690+
var result = names.Distinct().ToArray();
691+
if (ownMethodNames == null)
692+
{
693+
ownMethodNames = result;
694+
}
695+
696+
return result;
671697
}
672698

673699
private string[] GetAllPropertyNames()
@@ -727,7 +753,9 @@ private void UpdateMethodNames(out bool updated)
727753
if ((AllMethodNames == null) ||
728754
(target.Flags.HasFlag(HostTargetFlags.AllowExtensionMethods) && (ExtensionMethodSummary != engine.ExtensionMethodSummary)))
729755
{
730-
AllMethodNames = GetAllMethodNames();
756+
string[] ownMethodNames;
757+
AllMethodNames = GetAllMethodNames(out ownMethodNames);
758+
OwnMethodNames = ownMethodNames;
731759
updated = true;
732760
}
733761
else
@@ -1805,7 +1833,7 @@ string[] IDynamic.GetPropertyNames()
18051833

18061834
if (updatedFieldNames || updatedMethodNames || updatedPropertyNames || (AllMemberNames == null))
18071835
{
1808-
AllMemberNames = AllFieldNames.Concat(AllMethodNames).Concat(AllPropertyNames).ExcludeIndices().Distinct().ToArray();
1836+
AllMemberNames = AllFieldNames.Concat(EnumeratedMethodNames).Concat(AllPropertyNames).ExcludeIndices().Distinct().ToArray();
18091837
}
18101838

18111839
return AllMemberNames;

ClearScript/HostTargetMemberData.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ internal class HostTargetMemberData
7373

7474
public string[] AllFieldNames;
7575
public string[] AllMethodNames;
76+
public string[] OwnMethodNames;
7677
public string[] AllPropertyNames;
7778
public string[] AllMemberNames;
7879

ClearScript/ScriptEngine.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,11 @@ public object Invoke(string funcName, params object[] args)
11331133

11341134
#region internal members
11351135

1136+
internal virtual bool EnumerateExtensionMethods
1137+
{
1138+
get { return true; }
1139+
}
1140+
11361141
internal abstract void AddHostItem(string itemName, HostItemFlags flags, object item);
11371142

11381143
internal object PrepareResult<T>(T result, ScriptMemberFlags flags)
@@ -1368,6 +1373,11 @@ internal ExtensionMethodSummary ExtensionMethodSummary
13681373
get { return extensionMethodTable.Summary; }
13691374
}
13701375

1376+
internal void RebuildExtensionMethodSummary()
1377+
{
1378+
extensionMethodTable.RebuildSummary();
1379+
}
1380+
13711381
#endregion
13721382

13731383
#region bind cache

ClearScript/V8/ClearScriptV8/V8ContextImpl.cpp

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ V8ContextImpl::V8ContextImpl(V8IsolateImpl* pIsolateImpl, const StdString& name,
205205
m_hEnumeratorPropertyName = CreatePersistent(CreateString(StdString(L"enumerator")));
206206
m_hDonePropertyName = CreatePersistent(CreateString(StdString(L"done")));
207207
m_hValuePropertyName = CreatePersistent(CreateString(StdString(L"value")));
208+
m_hCachePropertyName = CreatePersistent(CreateString(StdString(L"{545a4a94-f37d-44bb-9e1e-bf3ce730c7e4}")));
208209
m_hAccessTokenName = CreatePersistent(CreateString(StdString(L"{cdc19e6e-5d80-4627-a605-bb4805f15086}")));
209210

210211
v8::Local<v8::Function> hGetIteratorFunction;
@@ -738,6 +739,7 @@ V8ContextImpl::~V8ContextImpl()
738739
Dispose(m_hHostObjectTemplate);
739740
Dispose(m_hAccessToken);
740741
Dispose(m_hAccessTokenName);
742+
Dispose(m_hCachePropertyName);
741743
Dispose(m_hValuePropertyName);
742744
Dispose(m_hDonePropertyName);
743745
Dispose(m_hEnumeratorPropertyName);
@@ -1312,10 +1314,19 @@ void V8ContextImpl::GetHostObjectProperty(v8::Local<v8::Name> hKey, const v8::Pr
13121314
{
13131315
BEGIN_PULSE_VALUE_SCOPE(&pContextImpl->m_DisableHostObjectInterception, true)
13141316

1315-
auto hNames = hHolder->GetOwnPropertyNames();
1316-
for (auto index = hNames->Length(); index > 0; index--)
1317+
auto hCache = hHolder->GetHiddenValue(pContextImpl->m_hCachePropertyName);
1318+
if (!hCache.IsEmpty())
13171319
{
1318-
hHolder->Delete(hNames->Get(index - 1));
1320+
if (hCache->IsObject())
1321+
{
1322+
auto hNames = hCache->ToObject()->GetOwnPropertyNames();
1323+
for (auto index = hNames->Length(); index > 0; index--)
1324+
{
1325+
hHolder->Delete(hNames->Get(index - 1));
1326+
}
1327+
}
1328+
1329+
hHolder->DeleteHiddenValue(pContextImpl->m_hCachePropertyName);
13191330
}
13201331

13211332
hHolder->SetHiddenValue(pContextImpl->m_hAccessTokenName, pContextImpl->m_hAccessToken);
@@ -1341,7 +1352,15 @@ void V8ContextImpl::GetHostObjectProperty(v8::Local<v8::Name> hKey, const v8::Pr
13411352
hResult = pContextImpl->ImportValue(HostObjectHelpers::GetProperty(::GetHostObject(info.Holder()), StdString(hName), isCacheable));
13421353
if (isCacheable)
13431354
{
1344-
hHolder->ForceSet(hName, hResult);
1355+
auto hCache = hHolder->GetHiddenValue(pContextImpl->m_hCachePropertyName);
1356+
if (hCache.IsEmpty() || !hCache->IsObject())
1357+
{
1358+
hCache = pContextImpl->CreateObject();
1359+
hHolder->SetHiddenValue(pContextImpl->m_hCachePropertyName, hCache);
1360+
}
1361+
1362+
hCache->ToObject()->ForceSet(hName, hResult);
1363+
hHolder->ForceSet(hName, hResult, v8::DontEnum);
13451364
}
13461365

13471366
CALLBACK_RETURN(hResult);

ClearScript/V8/ClearScriptV8/V8ContextImpl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ class V8ContextImpl: public V8Context
382382
Persistent<v8::String> m_hEnumeratorPropertyName;
383383
Persistent<v8::String> m_hDonePropertyName;
384384
Persistent<v8::String> m_hValuePropertyName;
385+
Persistent<v8::String> m_hCachePropertyName;
385386
Persistent<v8::String> m_hAccessTokenName;
386387
Persistent<v8::Object> m_hAccessToken;
387388
Persistent<v8::FunctionTemplate> m_hHostObjectTemplate;

ClearScript/V8/V8ScriptEngine.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ public sealed class V8ScriptEngine : ScriptEngine
9494
private readonly HostItemCollateral hostItemCollateral;
9595
private readonly IUniqueNameManager documentNameManager = new UniqueFileNameManager();
9696
private List<string> documentNames;
97+
private bool suppressExtensionMethodEnumeration;
9798

9899
#endregion
99100

@@ -419,6 +420,26 @@ public UIntPtr MaxRuntimeStackUsage
419420
}
420421
}
421422

423+
/// <summary>
424+
/// Gets or sets a value that controls extension method enumeration.
425+
/// </summary>
426+
/// <remarks>
427+
/// By default, all exposed extension methods appear as enumerable properties of all host
428+
/// objects, regardless of type. Setting this property to <c>true</c> excludes all
429+
/// extension methods from the list of enumerable properties of all host objects. Note that
430+
/// doing so affects only property enumeration; extension methods remain both retrievable
431+
/// and invocable regardless of this property's value.
432+
/// </remarks>
433+
public bool SuppressExtensionMethodEnumeration
434+
{
435+
get { return suppressExtensionMethodEnumeration; }
436+
set
437+
{
438+
suppressExtensionMethodEnumeration = value;
439+
RebuildExtensionMethodSummary();
440+
}
441+
}
442+
422443
/// <summary>
423444
/// Creates a compiled script.
424445
/// </summary>
@@ -665,6 +686,11 @@ public override void CollectGarbage(bool exhaustive)
665686

666687
#region ScriptEngine overrides (internal members)
667688

689+
internal override bool EnumerateExtensionMethods
690+
{
691+
get { return base.EnumerateExtensionMethods && !SuppressExtensionMethodEnumeration; }
692+
}
693+
668694
internal override void AddHostItem(string itemName, HostItemFlags flags, object item)
669695
{
670696
VerifyNotDisposed();

ClearScript/doc/Reference.chm

1.01 KB
Binary file not shown.

ClearScriptTest/BaseInterfaceMemberAccessTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ public void BaseInterfaceMemberAccess_ReadOnlyProperty_Write()
196196
[TestMethod, TestCategory("BaseInterfaceMemberAccess")]
197197
public void BaseInterfaceMemberAccess_Event()
198198
{
199-
engine.Execute("var connection = testObject.BaseInterfaceEvent.connect(function(sender, args) { sender.BaseInterfaceScalarProperty = args.Arg; })");
199+
engine.Execute("var connection = testObject.BaseInterfaceEvent.connect(function (sender, args) { sender.BaseInterfaceScalarProperty = args.Arg; })");
200200
testObject.BaseInterfaceFireEvent(5432);
201201
Assert.AreEqual(5432, testObject.BaseInterfaceScalarProperty);
202202
engine.Execute("connection.disconnect()");

ClearScriptTest/BaseMemberAccessTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ public void BaseMemberAccess_ReadOnlyProperty_Write()
280280
[TestMethod, TestCategory("BaseMemberAccess")]
281281
public void BaseMemberAccess_Event()
282282
{
283-
engine.Execute("var connection = testObject.BaseEvent.connect(function(sender, args) { sender.BaseScalarProperty = args.Arg; })");
283+
engine.Execute("var connection = testObject.BaseEvent.connect(function (sender, args) { sender.BaseScalarProperty = args.Arg; })");
284284
testObject.BaseFireEvent(5432);
285285
Assert.AreEqual(5432, testObject.BaseScalarProperty);
286286
engine.Execute("connection.disconnect()");

0 commit comments

Comments
 (0)