Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The JIT compiler encountered invalid IL code or an internal limitation #410

Open
cda963 opened this issue May 13, 2024 · 13 comments
Open

The JIT compiler encountered invalid IL code or an internal limitation #410

cda963 opened this issue May 13, 2024 · 13 comments

Comments

@cda963
Copy link

cda963 commented May 13, 2024

I'm using FastExpressionCompiler v2.0.0 along with Mapster (latest version) in a gRPC .Net Core project where I need to convert from a POCO object to a proto object, and everything works just fine.

When I try upgrading FastExpressionCompiler to any version above 2.0.0, the conversion throws an exception with the message "The JIT compiler encountered invalid IL code or an internal limitation".

Example: TenantConfig is my source object (a simple .Net object with a few string/boolean properties), and Protos.TenantConfig is the .proto equivalent of my .Net object:

var failure = new TenantConfig().Adapt<Protos.TenantConfig>();

@dadhi
Copy link
Owner

dadhi commented May 13, 2024

@cda963 Please provide the complete code for TenantConfig and Protos.TenantConfig. Every property matters, actually.

@cda963
Copy link
Author

cda963 commented May 13, 2024

This is my .Net object

public class TenantConfig
{
	public string Name { get; set; }

	public string Value { get; set; }

	public bool IsEncrypted { get; set; }
}

The Protos.TenantConfig is an auto-generated file based on the the following .proto file:

syntax = "proto3";

option csharp_namespace = "Kq.Protos";

package tenants;

service Tenants
{
	rpc TenantConfig (TenantConfigRequest) returns (TenantConfigResponse);
}

message TenantConfigRequest
{
	string tenantId = 1;
}

message TenantConfigResponse
{
	repeated TenantConfig TenantConfig = 1;
}

message TenantConfig
{
	string id = 1;
	string name = 2;
	string value = 3;
}

Below is the auto-generated file:

using System;
using System.CodeDom.Compiler;
using System.Diagnostics;
using Google.Protobuf;
using Google.Protobuf.Reflection;

namespace Kq.Protos;

public sealed class TenantConfig : IMessage<TenantConfig>, IMessage, IEquatable<TenantConfig>, IDeepCloneable<TenantConfig>, IBufferMessage
{
    private static readonly MessageParser<TenantConfig> _parser = new MessageParser<TenantConfig>(() => new TenantConfig());

    private UnknownFieldSet _unknownFields;

    public const int IdFieldNumber = 1;

    private string id_ = "";

    public const int NameFieldNumber = 2;

    private string name_ = "";

    public const int ValueFieldNumber = 3;

    private string value_ = "";

    [DebuggerNonUserCode]
    [GeneratedCode("protoc", null)]
    public static MessageParser<TenantConfig> Parser => _parser;

    [DebuggerNonUserCode]
    [GeneratedCode("protoc", null)]
    public static MessageDescriptor Descriptor => TenantsReflection.Descriptor.MessageTypes[13];

    [DebuggerNonUserCode]
    [GeneratedCode("protoc", null)]
    MessageDescriptor IMessage.Descriptor => Descriptor;

    [DebuggerNonUserCode]
    [GeneratedCode("protoc", null)]
    public string Id
    {
        get
        {
            return id_;
        }
        set
        {
            id_ = ProtoPreconditions.CheckNotNull(value, "value");
        }
    }

    [DebuggerNonUserCode]
    [GeneratedCode("protoc", null)]
    public string Name
    {
        get
        {
            return name_;
        }
        set
        {
            name_ = ProtoPreconditions.CheckNotNull(value, "value");
        }
    }

    [DebuggerNonUserCode]
    [GeneratedCode("protoc", null)]
    public string Value
    {
        get
        {
            return value_;
        }
        set
        {
            value_ = ProtoPreconditions.CheckNotNull(value, "value");
        }
    }

    [DebuggerNonUserCode]
    [GeneratedCode("protoc", null)]
    public TenantConfig()
    {
    }

    [DebuggerNonUserCode]
    [GeneratedCode("protoc", null)]
    public TenantConfig(TenantConfig other)
        : this()
    {
        id_ = other.id_;
        name_ = other.name_;
        value_ = other.value_;
        _unknownFields = UnknownFieldSet.Clone(other._unknownFields);
    }

    [DebuggerNonUserCode]
    [GeneratedCode("protoc", null)]
    public TenantConfig Clone()
    {
        return new TenantConfig(this);
    }

    [DebuggerNonUserCode]
    [GeneratedCode("protoc", null)]
    public override bool Equals(object other)
    {
        return Equals(other as TenantConfig);
    }

    [DebuggerNonUserCode]
    [GeneratedCode("protoc", null)]
    public bool Equals(TenantConfig other)
    {
        if (other == null)
        {
            return false;
        }

        if (other == this)
        {
            return true;
        }

        if (Id != other.Id)
        {
            return false;
        }

        if (Name != other.Name)
        {
            return false;
        }

        if (Value != other.Value)
        {
            return false;
        }

        return object.Equals(_unknownFields, other._unknownFields);
    }

    [DebuggerNonUserCode]
    [GeneratedCode("protoc", null)]
    public override int GetHashCode()
    {
        int num = 1;
        if (Id.Length != 0)
        {
            num ^= Id.GetHashCode();
        }

        if (Name.Length != 0)
        {
            num ^= Name.GetHashCode();
        }

        if (Value.Length != 0)
        {
            num ^= Value.GetHashCode();
        }

        if (_unknownFields != null)
        {
            num ^= _unknownFields.GetHashCode();
        }

        return num;
    }

    [DebuggerNonUserCode]
    [GeneratedCode("protoc", null)]
    public override string ToString()
    {
        return JsonFormatter.ToDiagnosticString(this);
    }

    [DebuggerNonUserCode]
    [GeneratedCode("protoc", null)]
    public void WriteTo(CodedOutputStream output)
    {
        output.WriteRawMessage(this);
    }

    [DebuggerNonUserCode]
    [GeneratedCode("protoc", null)]
    void IBufferMessage.InternalWriteTo(ref WriteContext output)
    {
        if (Id.Length != 0)
        {
            output.WriteRawTag(10);
            output.WriteString(Id);
        }

        if (Name.Length != 0)
        {
            output.WriteRawTag(18);
            output.WriteString(Name);
        }

        if (Value.Length != 0)
        {
            output.WriteRawTag(26);
            output.WriteString(Value);
        }

        if (_unknownFields != null)
        {
            _unknownFields.WriteTo(ref output);
        }
    }

    [DebuggerNonUserCode]
    [GeneratedCode("protoc", null)]
    public int CalculateSize()
    {
        int num = 0;
        if (Id.Length != 0)
        {
            num += 1 + CodedOutputStream.ComputeStringSize(Id);
        }

        if (Name.Length != 0)
        {
            num += 1 + CodedOutputStream.ComputeStringSize(Name);
        }

        if (Value.Length != 0)
        {
            num += 1 + CodedOutputStream.ComputeStringSize(Value);
        }

        if (_unknownFields != null)
        {
            num += _unknownFields.CalculateSize();
        }

        return num;
    }

    [DebuggerNonUserCode]
    [GeneratedCode("protoc", null)]
    public void MergeFrom(TenantConfig other)
    {
        if (other != null)
        {
            if (other.Id.Length != 0)
            {
                Id = other.Id;
            }

            if (other.Name.Length != 0)
            {
                Name = other.Name;
            }

            if (other.Value.Length != 0)
            {
                Value = other.Value;
            }

            _unknownFields = UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
        }
    }

    [DebuggerNonUserCode]
    [GeneratedCode("protoc", null)]
    public void MergeFrom(CodedInputStream input)
    {
        input.ReadRawMessage(this);
    }

    [DebuggerNonUserCode]
    [GeneratedCode("protoc", null)]
    void IBufferMessage.InternalMergeFrom(ref ParseContext input)
    {
        uint num;
        while ((num = input.ReadTag()) != 0)
        {
            switch (num)
            {
                default:
                    _unknownFields = UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
                    break;
                case 10u:
                    Id = input.ReadString();
                    break;
                case 18u:
                    Name = input.ReadString();
                    break;
                case 26u:
                    Value = input.ReadString();
                    break;
            }
        }
    }
}
#if false // Decompilation log
'430' items in cache
------------------
Resolve: 'System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Found single assembly: 'System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Load from: 'C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.3\ref\net8.0\System.Runtime.dll'
------------------
Resolve: 'Google.Protobuf, Version=3.23.1.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604'
Found single assembly: 'Google.Protobuf, Version=3.25.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604'
WARN: Version mismatch. Expected: '3.23.1.0', Got: '3.25.0.0'
Load from: 'C:\Users\Dragos\.nuget\packages\google.protobuf\3.25.0\lib\net5.0\Google.Protobuf.dll'
------------------
Resolve: 'Grpc.Core.Api, Version=2.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad'
Found single assembly: 'Grpc.Core.Api, Version=2.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad'
Load from: 'C:\Users\Dragos\.nuget\packages\grpc.core.api\2.62.0\lib\netstandard2.1\Grpc.Core.Api.dll'
------------------
Resolve: 'System.Collections, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Found single assembly: 'System.Collections, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Load from: 'C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.3\ref\net8.0\System.Collections.dll'
------------------
Resolve: 'System.Memory, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
Found single assembly: 'System.Memory, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
Load from: 'C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.3\ref\net8.0\System.Memory.dll'
------------------
Resolve: 'System.Runtime.InteropServices, Version=3.1.0.0, Culture=neutral, PublicKeyToken=null'
Found single assembly: 'System.Runtime.InteropServices, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
WARN: Version mismatch. Expected: '3.1.0.0', Got: '8.0.0.0'
Load from: 'C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.3\ref\net8.0\System.Runtime.InteropServices.dll'
------------------
Resolve: 'System.Runtime.CompilerServices.Unsafe, Version=3.1.0.0, Culture=neutral, PublicKeyToken=null'
Found single assembly: 'System.Runtime.CompilerServices.Unsafe, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
WARN: Version mismatch. Expected: '3.1.0.0', Got: '8.0.0.0'
Load from: 'C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.3\ref\net8.0\System.Runtime.CompilerServices.Unsafe.dll'
#endif

@dadhi
Copy link
Owner

dadhi commented May 13, 2024

Just to double-check. You still have the error with FEC v4.2.0?

@cda963
Copy link
Author

cda963 commented May 13, 2024

Yes, I just tried upgrading a couple of hours ago.

@dadhi
Copy link
Owner

dadhi commented May 13, 2024

Ok. I will check. The thing is simple so not sure what is going on here.

What are the TargetFrameworks?

@cda963
Copy link
Author

cda963 commented May 13, 2024

Thanks.

<TargetFramework>net8.0</TargetFramework>

@dadhi
Copy link
Owner

dadhi commented May 13, 2024

Ok, I do see the Id field in the Proto and no IsEncrypted.
How do they map?
What is Mapster Config for the mapping?

@cda963
Copy link
Author

cda963 commented May 13, 2024

Indeed I have changed last night the POCO properties and haven't updated the proto file.. this is what 14hrs work day does to you :). I'll test again and come back if this is still an issue. I apologize for this oversight.


Converting a single object works with v4.2.0, but converting a list of objects doesn't.

	var single = new TenantConfig
	{
		Name = Guid.NewGuid().ToString(),
		Value = Guid.NewGuid().ToString(),
		IsEncrypted = true
	}.Adapt<Protos.TenantConfig>();

	var list = new List<TenantConfig>()
	{
		new() 
		{
			Name = Guid.NewGuid().ToString(),
			Value = Guid.NewGuid().ToString(),
			IsEncrypted = true
		}
	};

	var exceptionHere = list.Adapt<List<Protos.TenantConfig>>();

I can work around this, by creating a list of converted objects.

@dadhi
Copy link
Owner

dadhi commented May 14, 2024

Ok, sorry to hear about your 14h wday. Will check the new example.

dadhi added a commit that referenced this issue May 15, 2024
@dadhi
Copy link
Owner

dadhi commented May 15, 2024

@cda963 I have added the list adapter to test and it is working fine. Check here 0f908c4

Maybe I am missing some details?

@cda963
Copy link
Author

cda963 commented May 15, 2024

In your test I see var failure = new TenantConfig().Adapt<TenantConfigVal>(); which tests for a simple object conversion, not a list. I couldn't find the part where you test against a list of objects.

@dadhi
Copy link
Owner

dadhi commented May 15, 2024

Yep, it is here

public void Issue410_The_JIT_compiler_encountered_invalid_IL_code_or_an_internal_limitation()

@cda963
Copy link
Author

cda963 commented May 15, 2024

Yes, I see it now.
The issue I'm facing is in a large solution with many projects.
Let me try this in an empty project, and I'll get back to you.
Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants