Return object instead of IList from ReplicationLogic#13323
Return object instead of IList from ReplicationLogic#13323aparajit-pratap merged 11 commits intoDynamoDS:emitMSILfrom
Conversation
|
@aparajit-pratap Looks like you simply replace the IList with object without any regressions (asides from mending a few tests) |
@pinzart90 I also made a few changes in the replication code. PTAL. I guess choosing IList was the wrong choice. I know better now :) |
src/Engine/EmitMSIL/Replication.cs
Outdated
| if (o.IsEnumerable) | ||
| { | ||
| return o.Value as IList<CLRStackValue>; | ||
| return o.Value as IList<CLRStackValue> ?? new List<CLRStackValue>() { o }; |
There was a problem hiding this comment.
I am trying to figure out why o.Value would not be IList<CLRStackValue>
The Marshaler should always convert enumerables to IList<CLRStackValue> I think...
There was a problem hiding this comment.
Well, in this particular function I still haven't encountered the case where o.Value is something other than IList<CLRStackValue> so I guess I can revert this but definitely in the other places I needed to check if the Value property was something other than IList<CLRStackValue>.
Did your question pertain to just this function or all such changes in general?
There was a problem hiding this comment.
Well...all cases of CLRStackValue.Value
If a CLRStackValue.IsEnumerable== true then I think all nested values should be wrapped in a List < CLRStackValues > (this is done by the ArrayMarshaler)
There was a problem hiding this comment.
We should not need to handle cases like if (o.IsEnumerable) { check if o is not IList<CLRStackValue>}
The root issue (as I interpret it) is that we currently do marshaling from CLR objects to CLRStackValue right at the beginning of ReplicationLogic. We do this marshaling without any consideration to the target types (i.e parameter types of functions)
The proper solution would be to stop doing this marshaling at the beginning of ReplicationLogic and only marshal function outputs then only unmarshal input arguments (considering the target parameter types) right before we invoke the functions.
There are 2 temporary solutions:
- Handle
ArrayListin Marshaling code (so that it can be considered an array...not a class pointer) - Stop unmarshaling to
ArrayListaltogether and go with something like List)I would go with option 2 since I remember we discussed this in the past, that the more performant ICollection implementation is List<> as opposed to ArrayList.
The quickest way would be to just convert from ArrayList to List (I can remove all ArrayList usage later on)
/// ProtoFFI.ArrayMarshaler /// internal override object UnMarshal(CLRStackValue dsObject, System.Type expectedCLRType, ProtoCore.MSILRuntimeCore runtimeCore) ............... if (collection is ArrayList arrList) { var list = Activator.CreateInstance(typeof(List<object>)); typeof(List<object>).GetMethod(nameof(List<object>.AddRange)).Invoke(list, new object[] { arrList.ToArray(typeof(object)) }); return list; } return collection;
| if (values.Count == 1) { return values[0]; } | ||
| return values; | ||
| var obj = n.GetCLRValue(p.Index, controller); | ||
| if (typeof(IEnumerable).IsAssignableFrom(obj.GetType())) |
There was a problem hiding this comment.
is it possible for o to be a string?
There was a problem hiding this comment.
o can be a string. but we check for that in o.IsEnumerable
| } | ||
| if (collection is Array) return collection; | ||
|
|
||
| if(elementType == typeof(int)) |
There was a problem hiding this comment.
as an alternative we could use
Array arr = null;
unsafe
{
arr = Array.CreateInstance(elementType, collection.Count);
}
collection.CopyTo(arr, 0);
return arr;
If we are ok with using unsafe...(the project would also need <AllowUnsafeBlocks>True</AllowUnsafeBlocks>)
There was a problem hiding this comment.
Is there any advantage to doing this? Is the advantage that it will support arbitrary types rather than just the primitive types that I have implemented?
There was a problem hiding this comment.
Pretty much just arbitrary types and less code.
There was a problem hiding this comment.
I was just curious - is there some way to convert to an array while avoiding iterating/copying the entire collection...
https://stackoverflow.com/questions/4972951/listt-to-t-without-copying
| } | ||
| if (elementType == typeof(double)) | ||
| { | ||
| return ConvertToTypedArray<double>(collection); |
There was a problem hiding this comment.
another alternative is to use collection.Cast< T >().ToArray(); instead of the custom ConvertToTypedArray function you implemented.
|
I think theres something to be gained by profiling and investigating ways to improve the performance of collection marshaling - but that seems like it's out of scope for this PR. |
pinzart90
left a comment
There was a problem hiding this comment.
LGTM
Please use whatever conversion method you think best.
| collection = (collection as ArrayList).ToArray(elementType); | ||
| collection = (collection as List<object>).ToArray(); | ||
| } | ||
| return Activator.CreateInstance(expectedCLRType, new[] { collection }); |
There was a problem hiding this comment.
@pinzart90 by your argument, wouldn't this existing code also be unsafe as this relies on there being a suitable constructor for whichever type is passed as expectedCLRType?
There was a problem hiding this comment.
Yes, I agree that it looks a bit unsafe.
Not sure what we could do, except try to get the constructor first and check if it exists
Or we could whitelist the expectedType (Array, ArrayList, List etc) - knowing that the constructors exist for these types
* return object instead of IList from ReplicationLogic * cleanup * fixes * cleanup * review comments * remove comment * replace ArrayList with List<object> * cleanup * revert unchanged files * try supporting casting to arrays of arbitrary types * review comments
Purpose
Return object instead of IList from ReplicationLogic
Hopefully this should address https://jira.autodesk.com/browse/DYN-5152
Declarations
Check these if you believe they are true
*.resxfilesRelease Notes
(FILL ME IN) Brief description of the fix / enhancement. Mandatory section
Reviewers
(FILL ME IN) Reviewer 1 (If possible, assign the Reviewer for the PR)
(FILL ME IN, optional) Any additional notes to reviewers or testers.
FYIs
(FILL ME IN, Optional) Names of anyone else you wish to be notified of