The JIT compiler encountered invalid IL code or an internal limitation
cda963 opened this issue · 14 comments
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>();
@cda963 Please provide the complete code for TenantConfig and Protos.TenantConfig. Every property matters, actually.
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
Just to double-check. You still have the error with FEC v4.2.0?
Yes, I just tried upgrading a couple of hours ago.
Ok. I will check. The thing is simple so not sure what is going on here.
What are the TargetFrameworks?
Thanks.
<TargetFramework>net8.0</TargetFramework>
Ok, I do see the Id
field in the Proto and no IsEncrypted
.
How do they map?
What is Mapster Config for the mapping?
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.
Ok, sorry to hear about your 14h wday. Will check the new example.
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.
Yep, it is here
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.
Closing, as it was not updated in quite some time