Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
fc7da1d
Adds test cases for member changes during a domain reload
BadSingleton Nov 9, 2020
72fafdd
!fixup add the project to the solution files
BadSingleton Nov 9, 2020
20861b2
Add more test cases
BadSingleton Nov 18, 2020
2253ef3
Merge remote-tracking branch 'upstream/master' into domain-reload-tes…
BadSingleton Nov 18, 2020
635edac
Make the tests run as netcoreapp
BadSingleton Nov 19, 2020
0ee931e
Remove stray colon
BadSingleton Nov 19, 2020
3dad96e
Rework the serialization of reflected types
BadSingleton Nov 19, 2020
90a81f3
Call PyType_Modified after modifying the type
BadSingleton Nov 20, 2020
10276f1
Some code review changes
BadSingleton Nov 20, 2020
4d0e2ce
fixup! Some code review changes
BadSingleton Nov 23, 2020
02fa245
Remove hungarian notation from Maybe* types
BadSingleton Nov 23, 2020
91c881c
Check the type of the exception before ignoring it
BadSingleton Nov 23, 2020
284e8e1
Check for validity, don't throw
BadSingleton Nov 23, 2020
fe96781
Refactor the member binding logic of ClassManager
BadSingleton Nov 23, 2020
6ff9e0b
Include info about why deserialization failed in Maybe*
BadSingleton Nov 23, 2020
4d2d05b
improve deserialization resolution of ref, out and in parameters
BadSingleton Nov 24, 2020
5f061bc
Clean up the project and solution files
BadSingleton Nov 26, 2020
3adc559
Merge branch 'master' into domain-reload-test-cases
BadSingleton Nov 26, 2020
e8543cf
Rework the serialization of reflected types
BadSingleton Nov 19, 2020
61b0d8c
Call PyType_Modified after modifying the type
BadSingleton Nov 20, 2020
c8bacf3
Some code review changes
BadSingleton Nov 20, 2020
cde5c23
fixup! Some code review changes
BadSingleton Nov 23, 2020
a956773
Remove hungarian notation from Maybe* types
BadSingleton Nov 23, 2020
ee3b391
Check the type of the exception before ignoring it
BadSingleton Nov 23, 2020
9b4d5f9
Check for validity, don't throw
BadSingleton Nov 23, 2020
a2f3294
Refactor the member binding logic of ClassManager
BadSingleton Nov 23, 2020
46dcb9d
Include info about why deserialization failed in Maybe*
BadSingleton Nov 23, 2020
10116bb
improve deserialization resolution of ref, out and in parameters
BadSingleton Nov 24, 2020
102054e
!fixup leftover error from the rebase
BadSingleton Nov 26, 2020
329de5d
Add fixes and test for nested classes
BadSingleton Nov 27, 2020
f97262b
Code review fixes
BadSingleton Dec 2, 2020
ceb3fab
Merge branch 'master' into domain-reload-test-cases-fixes
BadSingleton Dec 2, 2020
2d6ae4c
fixup! Merge branch 'master' into domain-reload-test-cases-fixes
BadSingleton Dec 2, 2020
16a39a6
fixup! Code review fixes
BadSingleton Dec 2, 2020
ace340d
Fix build failures on non-windows
BadSingleton Dec 8, 2020
78a8088
fixup! Fix build failures on non-windows
BadSingleton Dec 8, 2020
3232f79
Merge remote-tracking branch 'origin/domain-reload-test-cases-fixes' …
BadSingleton Dec 8, 2020
87287a5
Merge branch 'master' into domain-reload-test-cases-fixes
BadSingleton Dec 8, 2020
44b4800
Merge branch 'master' into domain-reload-test-cases-fixes
BadSingleton Dec 10, 2020
79516f1
Code review fixes
BadSingleton Dec 10, 2020
421f665
Merge remote-tracking branch 'upstream/master' into domain-reload-tes…
BadSingleton Dec 10, 2020
5e4c976
(WIP) rework project structure
BadSingleton Dec 11, 2020
9d1991a
Merge remote-tracking branch 'upstream/master' into domain-reload-tes…
BadSingleton Dec 14, 2020
bcf0cd6
Rework the projects file structure
BadSingleton Dec 14, 2020
73e5a6b
Check teh return value of PyDict_DelItemString
BadSingleton Dec 14, 2020
510a7ae
netstandard.dll is a Facade Library
BadSingleton Dec 16, 2020
21eb14c
Remove TestClassReference
BadSingleton Dec 17, 2020
59e81e2
Test runner docs fixes
BadSingleton Dec 17, 2020
1383b5a
Skip the domain reload tests on macos
BadSingleton Dec 17, 2020
fbc06ef
fixup! Skip the domain reload tests on macos
BadSingleton Dec 17, 2020
b3e86da
Update ISSUE_TEMPLATE.md
filmor Dec 17, 2020
0b027c6
refactoring in CreateSubType
lostmsu Dec 17, 2020
b4533c4
allocate space for GCHandle in instances of CLR Metatype (which are t…
lostmsu Dec 18, 2020
0a3f044
classderived: handle tp_dealloc called after tp_clear
lostmsu Dec 18, 2020
639236a
a few extra assertions
lostmsu Dec 18, 2020
3069285
fixed crash in finalizer of CLR types defined in Python, that survive…
lostmsu Dec 18, 2020
5c14aad
Merge branch 'master' into domain-reload-test-cases-fixes
BadSingleton Dec 18, 2020
00c19d5
Merge branch 'master' into domain-reload-test-cases-fixes
BadSingleton Jan 4, 2021
833e836
Fix break introduced by merge
BadSingleton Jan 4, 2021
62ae107
Code review fixes
BadSingleton Jan 4, 2021
eedbae5
Merge remote-tracking branch 'upstream/master' into domain-reload-tes…
BadSingleton Jan 5, 2021
73f39bc
Add the PID of the test runner
BadSingleton Jan 6, 2021
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
Prev Previous commit
Next Next commit
improve deserialization resolution of ref, out and in parameters
Also add a test
  • Loading branch information
BadSingleton committed Nov 24, 2020
commit 4d2d05b34b6890c96b661dad89ca6824b73902d0
78 changes: 78 additions & 0 deletions src/domain_tests/TestRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,84 @@ def after_reload():
print(bar.__repr__())
",
},

new TestCase
{
Name = "out_to_ref_param",
DotNetBefore = @"
Comment on lines +771 to +772
Copy link
Member

Choose a reason for hiding this comment

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

I'd suggest to add ref to out and in to ref test cases as well (in a separate PR; let's not clutter this one).

namespace TestNamespace
{

[System.Serializable]
public class Data
{
public int num = -1;
}

[System.Serializable]
public class Cls
{
public static void MyFn (out Data a)
{
a = new Data();
a.num = 9001;
}
}
}",
DotNetAfter = @"
namespace TestNamespace
{

[System.Serializable]
public class Data
{
public int num = -1;
}

[System.Serializable]
public class Cls
{
public static void MyFn (ref Data a)
{
a.num = 7;
}
}
}",
PythonCode = @"
import clr
import sys
clr.AddReference('DomainTests')
import TestNamespace
import System

def before_reload():

foo = TestNamespace.Data()
bar = TestNamespace.Cls.MyFn(foo)
assert bar.num == 9001
# foo shouldn't have changed.
assert foo.num == -1


def after_reload():

try:
# Now that the function takes a ref type, we must pass a valid object.
bar = TestNamespace.Cls.MyFn(None)
except System.NullReferenceException as e:
print('caught expected exception')
else:
raise AssertionError('failed to raise')

foo = TestNamespace.Data()
bar = TestNamespace.Cls.MyFn(foo)
# foo should have changed
assert foo.num == 7
assert bar.num == 7
# Pythonnet also returns a new object with `ref`-quialified parameters
Copy link
Contributor

Choose a reason for hiding this comment

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

*qualified

assert foo is not bar
",
},
};

/// <summary>
Expand Down
5 changes: 4 additions & 1 deletion src/domain_tests/test_domain_reload.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,7 @@ def test_rename_event():

@pytest.mark.xfail(reason="newly instanced object uses PyType_GenericAlloc")
def test_construct_removed_class():
_run_test("construct_removed_class")
_run_test("construct_removed_class")

def test_out_to_ref_param():
_run_test("out_to_ref_param")
77 changes: 65 additions & 12 deletions src/runtime/StateSerialization/MaybeMethodBase.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,50 @@
using System;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Linq;

namespace Python.Runtime
{
[Serializable]
internal struct MaybeMethodBase<T> : ISerializable where T: MethodBase
{
[Serializable]
struct ParameterHelper : IEquatable<ParameterInfo>
{
public enum TypeModifier
{
None,
In,
Out,
Ref
}
public readonly string Name;
public readonly TypeModifier Modifier;

public ParameterHelper(ParameterInfo tp)
{
Name = tp.ParameterType.AssemblyQualifiedName;
Modifier = TypeModifier.None;

if (tp.IsIn)
{
Modifier = TypeModifier.In;
}
else if (tp.IsOut)
{
Modifier = TypeModifier.Out;
}
Comment on lines +38 to +45
Copy link
Member

Choose a reason for hiding this comment

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

I am not sure these mean what you think they do. See the recent PR #1308 . Can't find corresponding spec, but I suspect for out you need to check ParameterType.IsByRef + IsOut.

This is also the reason why I suggested to add extra tests later.

BTW, this can be fixed in a separate PR.

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 wasn't aware of those Attributes. And yes, we'd need to check for ByRef as a parameter with the attribute would be int, not int&. I'll do that in that another PR (along with more tests).

else if (tp.ParameterType.IsByRef)
{
Modifier = TypeModifier.Ref;
}
}

public bool Equals(ParameterInfo other)
{
return this.Equals(new ParameterHelper(other));
}
}
public static implicit operator MaybeMethodBase<T> (T ob) => new MaybeMethodBase<T>(ob);

string name;
Expand Down Expand Up @@ -64,11 +100,11 @@ internal MaybeMethodBase(SerializationInfo serializationInfo, StreamingContext c
var tp = Type.GetType(serializationInfo.GetString("t"));
// Get the method's parameters types
var field_name = serializationInfo.GetString("f");
var param = (string[])serializationInfo.GetValue("p", typeof(string[]));
var param = (ParameterHelper[])serializationInfo.GetValue("p", typeof(ParameterHelper[]));
Type[] types = new Type[param.Length];
for (int i = 0; i < param.Length; i++)
{
types[i] = Type.GetType(param[i]);
types[i] = Type.GetType(param[i].Name);
}
// Try to get the method
MethodBase mb = tp.GetMethod(field_name, ClassManager.BindingFlags, binder:null, types:types, modifiers:null);
Expand All @@ -81,7 +117,29 @@ internal MaybeMethodBase(SerializationInfo serializationInfo, StreamingContext c
// Do like in ClassManager.GetClassInfo
if(mb != null && ClassManager.ShouldBindMethod(mb))
{
info = mb;
// One more step: Changing:
// void MyFn (ref int a)
// to:
// void MyFn (out int a)
// will still find the fucntion correctly as, `in`, `out` and `ref`
// are all represented as a reference type. Query the method we got
// and validate the parameters
bool matches = true;
if (param.Length != 0)
{
foreach (var item in Enumerable.Zip(param, mb.GetParameters(), (x, y) => new {x, y}))
{
if (!item.x.Equals(item.y))
{
matches = false;
break;
}
}
}
if (matches)
{
info = mb;
}
}
}
catch (Exception e)
Expand All @@ -97,13 +155,8 @@ public void GetObjectData(SerializationInfo serializationInfo, StreamingContext
{
serializationInfo.AddValue("f", info.Name);
serializationInfo.AddValue("t", info.ReflectedType.AssemblyQualifiedName);
var p = info.GetParameters();
string[] types = new string[p.Length];
for (int i = 0; i < p.Length; i++)
{
types[i] = p[i].ParameterType.AssemblyQualifiedName;
}
serializationInfo.AddValue("p", types, typeof(string[]));
ParameterHelper[] parameters = (from p in info.GetParameters() select new ParameterHelper(p)).ToArray();
serializationInfo.AddValue("p", parameters, typeof(ParameterHelper[]));
}
}
}
Expand Down
13 changes: 13 additions & 0 deletions src/runtime/methodbinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,19 @@ int IComparer<MaybeMethodBase>.Compare(MaybeMethodBase m1, MaybeMethodBase m2)
{
MethodBase me1 = m1.Valid ? m1.Value : null;
MethodBase me2 = m2.Valid ? m2.Value : null;
if (me1 == null && me2 == null)
{
return 0;
}
else if (me1 == null)
{
return -1;
}
else if (me2 == null)
{
return 1;
}

if (me1.DeclaringType != me2.DeclaringType)
{
// m2's type derives from m1's type, favor m2
Expand Down