IL2CPU icon indicating copy to clipboard operation
IL2CPU copied to clipboard

Use ref locals to get class fields in Plugs

Open fanoI opened this issue 7 years ago • 1 comments

When there is the need to access a field of a class you have to add a ref variable to one of its plug method and use the attribute "FieldAccess" this could be easily become ugly when you need to access a lot of fields:

public static void Ctor(StreamWriter aThis, string path, bool append, Encoding encoding, int bufferSize,
                         [FieldAccess(Name = "System.IO.Stream System.IO.StreamWriter._stream")] ref Stream _stream,
                         [FieldAccess(Name = "System.Int32 System.IO.StreamWriter._charPos")] ref int _charPos,
                         [FieldAccess(Name = "System.Char[] System.IO.StreamWriter._charBuffer")] ref int _charLen,
                         [FieldAccess(Name = "System.Char[] System.IO.StreamWriter._charBuffer")] ref char[] _charBuffer,
                         [FieldAccess(Name = "System.Byte[] System.IO.StreamWriter._byteBuffer")] ref byte[] _byteBuffer,
                         [FieldAccess(Name = "System.Char[] System.IO.TextWriter.CoreNewLine")] ref char[] CoreNewLine
                        )

I've had two constructors to plug (one that take a String representing a File Path and an other in which you pass a Stream already created) and so the ideal solution would have been to use an utility function to initialize all the field but I will have to pass all the ref variables and their value to it that well defeat the purpose of it a lot!

My idea is leaving the attribute version for the old code (or replace it if we are so brave) and to use ref locals introduced in C# 7 to resolve this problem so the Init() would become:

private static void Init(Stream stream, bool append, CosmosEncoding encoding, int bufferSize,  bool shouldLeaveOpen) 
{
    ref Stream _stream = ref GetFieldAccess("System.IO.Stream System.IO.StreamWriter._stream");
    ref int _charPos = ref GetFieldAccess("System.Int32 System.IO.StreamWriter._charPos");
    ref char[] _charBuffer = ref GetFieldAccess("System.Char[] System.IO.StreamWriter._charBuffer");
    ref byte[] _byteBuffer = ref  GetFieldAccess("System.Byte[] System.IO.StreamWriter._byteBuffer");
    ref char[] CoreNewLine = ref  GetFieldAccess("System.Char[] System.IO.TextWriter.CoreNewLine");

    _stream = stream;
    [...]
}      

GetFieldAccess should have these prototypes:

ref object GetFieldAccess(String FieldName);
ref object[] GetFieldAccess(String FieldName);
unsafe ref void *GetFieldAccess(String FieldName); // Not working in C# 7.0 should be added in future releases

fanoI avatar Nov 03 '17 13:11 fanoI

Another way make easier to access to field is to add the possibility to plug a field explicitly without the needed of a plug method.

Taking this example again one could write:

public static class StreamWriterImpl
{
[PlugField name="System.IO.Stream System.IO.StreamWriter._stream"] Stream stream;

With a little of compiler "trickery" we will obtain that: stream wouldn't change it wouldn't even be compiled if we want when loading or storing that field, the compiler would load or store _stream instead.

fanoI avatar Nov 03 '17 16:11 fanoI