Skip to content

Commit cfe008b

Browse files
authored
Misc changes (#949)
* Use string.GetPinnableReference * Don't save the RegExp.Match instance * Misc mmap changes * Remove #if check * Use Assembly.Location instead of Assembly.Codebase * Fix test_reachtype * Fix test_formatting * Use GenerateDocumentationFile * Use UseDotNet@2 task on VSTS * ipy.sh on macOS * Use != true instead of == false * Fix concurrency issue in winreg * Hide ctypes.dlopen on Windows * Remove silverlight comment
1 parent 74e5774 commit cfe008b

18 files changed

Lines changed: 103 additions & 87 deletions

File tree

Build/steps.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,17 @@ steps:
2424
Write-Host ("##vso[task.setvariable variable=PackageVersion;isSecret=false;isOutput=true;]$PackageVersion")
2525
displayName: Grab Package Version
2626
27-
- task: DotNetCoreInstaller@1
27+
- task: UseDotNet@2
2828
displayName: Install .NET Core 2.1 runtime for running tests
2929
inputs:
3030
packageType: 'runtime'
3131
version: '2.1.x'
3232

33-
- task: DotNetCoreInstaller@1
33+
- task: UseDotNet@2
3434
displayName: Install .NET Core 3.1 SDK for build
3535
inputs:
3636
packageType: 'sdk'
37-
version: '3.1.302'
37+
version: '3.1.x'
3838

3939
# Set Mono version on macOS
4040
- ${{ if eq(parameters.os, 'macOS') }}:

Src/IronPython.Modules/IronPython.Modules.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<TargetFrameworks>net46;netcoreapp2.1;netcoreapp3.1;netstandard2.0</TargetFrameworks>
55
<BaseAddress>885063680</BaseAddress>
66
<CodeAnalysisRuleSet>..\..\IronPython.ruleset</CodeAnalysisRuleSet>
7-
<DocumentationFile>$(OutputPath)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
7+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
88
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
99
</PropertyGroup>
1010

@@ -14,7 +14,7 @@
1414
<HintPath>..\..\Util\References\Mono.Posix.dll</HintPath>
1515
</Reference>
1616
</ItemGroup>
17-
<ItemGroup Condition=" '$(IsFullFramework)' == 'false' ">
17+
<ItemGroup Condition=" '$(IsFullFramework)' != 'true' ">
1818
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
1919
</ItemGroup>
2020

Src/IronPython.Modules/_ctypes/CFuncPtr.cs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ public _CFuncPtr(int handle) {
140140
/// <summary>
141141
/// Creates a new CFuncPtr with the specfied address.
142142
/// </summary>
143-
public _CFuncPtr([NotNull]BigInteger handle) {
143+
public _CFuncPtr([NotNull] BigInteger handle) {
144144
_memHolder = new MemoryHolder(IntPtr.Size);
145145
addr = new IntPtr((long)handle);
146146
_id = Interlocked.Increment(ref _curId);
@@ -762,6 +762,8 @@ public PrimitiveMarshaller(Expression/*!*/ container, Type/*!*/ type)
762762
_type = type;
763763
}
764764

765+
private static readonly MethodInfo StringGetPinnableReference = typeof(string).GetMethod("GetPinnableReference");
766+
765767
public override MarshalCleanup EmitCallStubArgument(ILGenerator/*!*/ generator, int argIndex, List<object>/*!*/ constantPool, int constantPoolArgument) {
766768
if (_type == typeof(DynamicNull)) {
767769
generator.Emit(OpCodes.Ldc_I4_0);
@@ -779,12 +781,18 @@ public override MarshalCleanup EmitCallStubArgument(ILGenerator/*!*/ generator,
779781
// but we need the string to be pinned longer than the duration of the the CLR's
780782
// p/invoke. This is because the function could return the same pointer back
781783
// to us and we need to create a new string from it.
782-
LocalBuilder lb = generator.DeclareLocal(typeof(string), true);
783-
generator.Emit(OpCodes.Stloc, lb);
784-
generator.Emit(OpCodes.Ldloc, lb);
785-
generator.Emit(OpCodes.Conv_I);
786-
generator.Emit(OpCodes.Ldc_I4, RuntimeHelpers.OffsetToStringData);
787-
generator.Emit(OpCodes.Add);
784+
if (StringGetPinnableReference is null) {
785+
LocalBuilder lb = generator.DeclareLocal(typeof(string), true);
786+
generator.Emit(OpCodes.Stloc, lb);
787+
generator.Emit(OpCodes.Ldloc, lb);
788+
generator.Emit(OpCodes.Conv_I);
789+
#pragma warning disable CS0618 // Type or member is obsolete
790+
generator.Emit(OpCodes.Ldc_I4, RuntimeHelpers.OffsetToStringData);
791+
#pragma warning restore CS0618 // Type or member is obsolete
792+
generator.Emit(OpCodes.Add);
793+
} else {
794+
generator.Emit(OpCodes.Call, StringGetPinnableReference);
795+
}
788796
} else if (_type == typeof(Bytes)) {
789797
LocalBuilder lb = generator.DeclareLocal(typeof(byte).MakeByRefType(), true);
790798
generator.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod(nameof(ModuleOps.GetBytes)));

Src/IronPython.Modules/_ctypes/SimpleType.cs

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@
77
using System;
88
using System.Collections.Generic;
99
using System.Numerics;
10+
using System.Reflection;
1011
using System.Reflection.Emit;
1112
using System.Runtime.CompilerServices;
1213
using System.Runtime.InteropServices;
1314

14-
using Microsoft.Scripting;
15-
using Microsoft.Scripting.Runtime;
16-
1715
using IronPython.Runtime;
1816
using IronPython.Runtime.Operations;
1917
using IronPython.Runtime.Types;
2018

19+
using Microsoft.Scripting.Runtime;
20+
2121
namespace IronPython.Modules {
2222
/// <summary>
2323
/// Provides support for interop with native code from Python code.
@@ -344,6 +344,8 @@ object INativeType.SetValue(MemoryHolder/*!*/ owner, int offset, object value) {
344344
throw new InvalidOperationException();
345345
}
346346

347+
private static readonly MethodInfo StringGetPinnableReference = typeof(string).GetMethod("GetPinnableReference");
348+
347349
MarshalCleanup INativeType.EmitMarshalling(ILGenerator/*!*/ method, LocalOrArg argIndex, List<object>/*!*/ constantPool, int constantPoolArgument) {
348350
MarshalCleanup cleanup = null;
349351
Label marshalled = method.DefineLabel();
@@ -415,12 +417,18 @@ MarshalCleanup INativeType.EmitMarshalling(ILGenerator/*!*/ method, LocalOrArg a
415417
method.Emit(OpCodes.Dup);
416418
method.Emit(OpCodes.Brfalse, nextTry);
417419

418-
LocalBuilder lb = method.DeclareLocal(typeof(string), true);
419-
method.Emit(OpCodes.Stloc, lb);
420-
method.Emit(OpCodes.Ldloc, lb);
421-
method.Emit(OpCodes.Conv_I);
422-
method.Emit(OpCodes.Ldc_I4, RuntimeHelpers.OffsetToStringData);
423-
method.Emit(OpCodes.Add);
420+
if (StringGetPinnableReference is null) {
421+
LocalBuilder lb = method.DeclareLocal(typeof(string), true);
422+
method.Emit(OpCodes.Stloc, lb);
423+
method.Emit(OpCodes.Ldloc, lb);
424+
method.Emit(OpCodes.Conv_I);
425+
#pragma warning disable CS0618 // Type or member is obsolete
426+
method.Emit(OpCodes.Ldc_I4, RuntimeHelpers.OffsetToStringData);
427+
#pragma warning restore CS0618 // Type or member is obsolete
428+
method.Emit(OpCodes.Add);
429+
} else {
430+
method.Emit(OpCodes.Call, StringGetPinnableReference);
431+
}
424432
method.Emit(OpCodes.Br, done);
425433

426434
method.MarkLabel(nextTry);
@@ -518,7 +526,6 @@ internal static void MarshalWCharPointer(ILGenerator method, LocalOrArg argIndex
518526
Type argumentType = argIndex.Type;
519527
Label isNull;
520528
Label done;
521-
LocalBuilder lb;
522529
isNull = method.DefineLabel();
523530
done = method.DefineLabel();
524531
method.Emit(OpCodes.Brfalse, isNull);
@@ -527,12 +534,19 @@ internal static void MarshalWCharPointer(ILGenerator method, LocalOrArg argIndex
527534
method.Emit(OpCodes.Box, argumentType);
528535
}
529536

530-
lb = method.DeclareLocal(typeof(string), true);
531-
method.Emit(OpCodes.Stloc, lb);
532-
method.Emit(OpCodes.Ldloc, lb);
533-
method.Emit(OpCodes.Conv_I);
534-
method.Emit(OpCodes.Ldc_I4, RuntimeHelpers.OffsetToStringData);
535-
method.Emit(OpCodes.Add);
537+
if (StringGetPinnableReference is null) {
538+
LocalBuilder lb = method.DeclareLocal(typeof(string), true);
539+
method.Emit(OpCodes.Stloc, lb);
540+
method.Emit(OpCodes.Ldloc, lb);
541+
method.Emit(OpCodes.Conv_I);
542+
#pragma warning disable CS0618 // Type or member is obsolete
543+
method.Emit(OpCodes.Ldc_I4, RuntimeHelpers.OffsetToStringData);
544+
#pragma warning restore CS0618 // Type or member is obsolete
545+
method.Emit(OpCodes.Add);
546+
}
547+
else {
548+
method.Emit(OpCodes.Call, StringGetPinnableReference);
549+
}
536550
method.Emit(OpCodes.Br, done);
537551

538552
method.MarkLabel(isNull);

Src/IronPython.Modules/_ctypes/_ctypes.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ public static object LoadLibrary(string library, int mode = 0) {
196196
return res.ToPython();
197197
}
198198

199-
// Provided for Posix compat.
199+
[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
200200
public static object dlopen(string library, int mode = 0) {
201201
return LoadLibrary(library, mode);
202202
}

Src/IronPython.Modules/mmap.cs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System;
88
using System.Collections.Generic;
99
using System.ComponentModel;
10+
using System.Diagnostics;
1011
using System.Globalization;
1112
using System.IO;
1213
using System.IO.MemoryMappedFiles;
@@ -76,13 +77,13 @@ public static PythonType mmap {
7677
}
7778
}
7879

79-
[PythonType("mmap.mmap"), PythonHidden]
80+
[PythonType("mmap"), PythonHidden]
8081
public class MmapUnix : MmapDefault {
81-
public MmapUnix(CodeContext/*!*/ context, int fileno, long length, string tagname = null, int access = ACCESS_WRITE, long offset = 0, int flags = MAP_SHARED, int prot = PROT_WRITE | PROT_READ)
82-
: base(context, fileno, length, tagname, access, offset) { }
82+
public MmapUnix(CodeContext/*!*/ context, int fileno, long length, int flags = MAP_SHARED, int prot = PROT_WRITE | PROT_READ, int access = ACCESS_WRITE, long offset = 0)
83+
: base(context, fileno, length, null, access, offset) { }
8384
}
8485

85-
[PythonType("mmap.mmap"), PythonHidden]
86+
[PythonType("mmap"), PythonHidden]
8687
public class MmapDefault : IWeakReferenceable {
8788
private MemoryMappedFile _file;
8889
private MemoryMappedViewAccessor _view;
@@ -136,11 +137,12 @@ public MmapDefault(CodeContext/*!*/ context, int fileno, long length, string tag
136137
_sourceStream = null;
137138

138139
// work around the .NET bug whereby CreateOrOpen throws on a null mapName
139-
if (_mapName == null) {
140-
_mapName = Guid.NewGuid().ToString();
140+
if (_mapName is null) {
141+
_file = MemoryMappedFile.CreateNew(null, length, _fileAccess);
142+
} else {
143+
Debug.Assert(RuntimeInformation.IsOSPlatform(OSPlatform.Windows));
144+
_file = MemoryMappedFile.CreateOrOpen(_mapName, length, _fileAccess);
141145
}
142-
143-
_file = MemoryMappedFile.CreateOrOpen(_mapName, length, _fileAccess);
144146
} else {
145147
// Memory-map an actual file
146148
_offset = offset;

Src/IronPython.Modules/re.cs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -350,18 +350,17 @@ public object sub(CodeContext/*!*/ context, object repl, object @string, int cou
350350

351351
string replacement = ValidateReplacement(repl);
352352

353-
RegExpMatch prev = null;
353+
int prevEnd = -1;
354354
string input = ValidateString(@string);
355355
return ToPatternType(_re.Replace(
356356
input,
357357
delegate (RegExpMatch match) {
358358
// from the docs: Empty matches for the pattern are replaced
359359
// only when not adjacent to a previous match
360-
if (string.IsNullOrEmpty(match.Value) && prev != null &&
361-
(prev.Index + prev.Length) == match.Index) {
360+
if (string.IsNullOrEmpty(match.Value) && match.Index == prevEnd) {
362361
return "";
363362
};
364-
prev = match;
363+
prevEnd = match.Index + match.Length;
365364

366365
if (replacement != null) return UnescapeGroups(match, replacement);
367366
return PythonCalls.Call(context, repl, Match.Make(match, this, input)) as string;
@@ -378,18 +377,17 @@ public PythonTuple subn(CodeContext/*!*/ context, object repl, object @string, i
378377
string res;
379378
string replacement = ValidateReplacement(repl);
380379

381-
RegExpMatch prev = null;
380+
int prevEnd = -1;
382381
string input = ValidateString(@string);
383382
res = _re.Replace(
384383
input,
385384
delegate (RegExpMatch match) {
386385
// from the docs: Empty matches for the pattern are replaced
387386
// only when not adjacent to a previous match
388-
if (string.IsNullOrEmpty(match.Value) && prev != null &&
389-
(prev.Index + prev.Length) == match.Index) {
387+
if (string.IsNullOrEmpty(match.Value) && match.Index == prevEnd) {
390388
return "";
391389
};
392-
prev = match;
390+
prevEnd = match.Index + match.Length;
393391

394392
totalCount++;
395393
if (replacement != null) return UnescapeGroups(match, replacement);

Src/IronPython.Modules/winreg.cs

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the Apache 2.0 License.
33
// See the LICENSE file in the project root for more information.
4-
#if FEATURE_REGISTRY //Registry not available in silverlight and we require .NET 4.0 APIs for implementing this.
54

5+
#if FEATURE_REGISTRY
6+
7+
using Microsoft.Win32;
8+
using Microsoft.Win32.SafeHandles;
69
using System;
7-
using System.Collections.Generic;
10+
using System.Collections.Concurrent;
811
using System.ComponentModel;
912
using System.Diagnostics;
1013
using System.IO;
@@ -14,12 +17,8 @@
1417
using System.Security.AccessControl;
1518
using System.Text;
1619

17-
using Microsoft.Win32;
18-
using Microsoft.Win32.SafeHandles;
19-
2020
using IronPython.Runtime;
2121
using IronPython.Runtime.Exceptions;
22-
using IronPython.Runtime.Operations;
2322
using IronPython.Runtime.Types;
2423

2524
[assembly: PythonModule("winreg", typeof(IronPython.Modules.PythonWinReg), PlatformsAttribute.PlatformFamily.Windows)]
@@ -444,10 +443,8 @@ public static PythonTuple QueryInfoKey(object key) {
444443
HKEYType rootKey = null;
445444
//The key can also be a handle. If it is, then retrieve it from the cache.
446445
if (key is int) {
447-
if (HKeyHandleCache.cache.ContainsKey((int)key)) {
448-
if (HKeyHandleCache.cache[(int)key].IsAlive) {
449-
rootKey = HKeyHandleCache.cache[(int)key].Target as HKEYType;
450-
}
446+
if (HKEYType.cache.TryGetValue((int)key, out var value)) {
447+
value.TryGetTarget(out rootKey);
451448
}
452449
} else {
453450
rootKey = GetRootKey(key);
@@ -640,10 +637,15 @@ private static int MapRegistryValueKind(RegistryValueKind registryValueKind) {
640637

641638
[PythonType]
642639
public class HKEYType : IDisposable {
640+
//CPython exposes the native handle for the registry keys as well. Since there is no .NET API to
641+
//expose the native handle, we return the hashcode of the key as the "handle". To track these handles
642+
//and return the right RegistryKey we maintain this cache of the generated handles.
643+
internal static readonly ConcurrentDictionary<int, WeakReference<HKEYType>> cache = new ConcurrentDictionary<int, WeakReference<HKEYType>>();
644+
643645
private RegistryKey key;
644646
internal HKEYType(RegistryKey key) {
645647
this.key = key;
646-
HKeyHandleCache.cache[key.GetHashCode()] = new WeakReference(this);
648+
cache[key.GetHashCode()] = new WeakReference<HKEYType>(this);
647649
}
648650

649651
internal readonly BigInteger hkey = 0;
@@ -654,7 +656,7 @@ internal HKEYType(RegistryKey key, BigInteger hkey) : this(key) {
654656
public void Close() {
655657
lock (this) {
656658
if (key != null) {
657-
HKeyHandleCache.cache.Remove(key.GetHashCode());
659+
cache.TryRemove(key.GetHashCode(), out _);
658660
key.Dispose();
659661
key = null;
660662
}
@@ -703,15 +705,6 @@ void IDisposable.Dispose() {
703705
#endregion
704706
}
705707
}
706-
707-
//CPython exposes the native handle for the registry keys as well. Since there is no .NET API to
708-
//expose the native handle, we return the hashcode of the key as the "handle". To track these handles
709-
//and return the right RegistryKey we maintain this cache of the generated handles.
710-
internal static class HKeyHandleCache {
711-
internal static Dictionary<int, WeakReference> cache = new Dictionary<int, WeakReference>();
712-
713-
}
714-
715708
}
716709

717710
#endif

Src/IronPython.Wpf/IronPython.Wpf.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
<TargetFrameworks>net46</TargetFrameworks>
77
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);netcoreapp3.1</TargetFrameworks>
88
<DocumentationFile>$(OutputPath)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
9-
<BaseAddress>885063680</BaseAddress>
109
<StoreInDLLs>true</StoreInDLLs>
1110
<UseWPF Condition=" '$(OS)' == 'Windows_NT' ">true</UseWPF>
1211
</PropertyGroup>

Src/IronPython/IronPython.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<TargetFrameworks>net46;netcoreapp2.1;netcoreapp3.1;netstandard2.0</TargetFrameworks>
55
<BaseAddress>879755264</BaseAddress>
66
<CodeAnalysisRuleSet>..\..\IronPython.ruleset</CodeAnalysisRuleSet>
7-
<DocumentationFile>$(OutputPath)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
7+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
88
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
99
</PropertyGroup>
1010

@@ -27,7 +27,7 @@
2727
<HintPath>..\..\Util\References\Mono.Posix.dll</HintPath>
2828
</Reference>
2929
</ItemGroup>
30-
<ItemGroup Condition=" '$(IsFullFramework)' == 'false' ">
30+
<ItemGroup Condition=" '$(IsFullFramework)' != 'true' ">
3131
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
3232
</ItemGroup>
3333

0 commit comments

Comments
 (0)