1

I'm making a .NET-compatible compiler and today I have come across a very strange bug. I'm testing field getters and sometimes I get MissingFieldException with some of the built-in types' fields.

The fields I'm troubled with are:

  • MaxValue of all numerics
  • MinValue of all numerics
  • double.PositiveInfinity
  • double.NegativeInfinity
  • double.NaN

The code compiles fine: during compilation, the FieldInfo is found and a corresponding ldsfld is emitted. During the run phase, however, the aforementioned exception is being thrown. And this happens only for some fields: Type.EmptyTypes compiles and works just as expected!

I tried to investigate the IL-code which csc emits for those fields, but it does some optimizations and the program just pushes the actual value to the stack instead of calling the field. While this is, apparently, a more efficient way, for now I would like to keep my compiler as simple as possible.

Has anyone came across similar issues?

Impworks
  • 2,647
  • 3
  • 25
  • 53
  • It would really help if you could give a single specific but complete example. – Jon Skeet Mar 03 '13 at 20:32
  • Can you post your code. – ChrisF Mar 03 '13 at 20:32
  • The compiler is quite huge and most of its code is irrelevant to the subject. The emit code is as simple as this: `gen.Emit(OpCodes.Ldsfld, fieldInfo);`. Debugging shows that during compile time the `fieldInfo` value contains the valid `FieldInfo` object. – Impworks Mar 03 '13 at 21:36

1 Answers1

0

I tried to investigate the IL-code which csc emits for those fields, but it does some optimizations and the program just pushes the actual value to the stack instead of calling the field.

All the fields in your list are constant fields. Therefore their values will be copied into the IL generated from code referencing them.

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
  • But the field does exist. I tried the following code: `var pty = typeof(int).GetField("MaxValue");` `var result = pty.GetValue(null);` and it gave the result. – Impworks Mar 03 '13 at 21:32
  • I agree the field does exist. I'm not sure I understand exactly how you arrive at your `MissingFieldException`. You say you're testing "field getters". What are those? I can only say that if you write code which "reads" `int.MaxValue` directly, like `int myInt = int.MaxValue;`, then the IL will not contain a read of the field. The field is constant (`.IsLiteral` returns `true`). The value will be hard-coded into the IL instead. On the other hand, `var e = Type.EmptyTypes;` will compile into IL that actually reads the run-time value of `EmptyTypes`. `EmptyTypes` is not constant (literal). – Jeppe Stig Nielsen Mar 03 '13 at 21:42
  • So you're saying that if a field has the flag `IsLiteral` raised, its value cannot be retrieved via `ldsfld` and **must** be hard-coded into the IL? – Impworks Mar 04 '13 at 04:50
  • I decided to stick with that method after all. Seems to work. Thank you! – Impworks Mar 04 '13 at 07:38
  • I'm glad you found a solution. I'm no expert in IL, I just know that the C# compiler translates uses of constant fields into "hard-coded" values in the IL. It looks like the thread [What's the different between `ldsfld` and `ldstr` in IL?](http://stackoverflow.com/questions/3674288/) is related. Note that [`string.Empty`](http://msdn.microsoft.com/en-us/library/system.string.empty) is ***not*** marked constant/literal, whereas using the (compile-time constant) string literal `""` in the C# source code is equivalent to using a constant/literal field with the value `""`. – Jeppe Stig Nielsen Mar 04 '13 at 12:12
  • It seems that literal fields can only be of primitive numeric types. Therefore `DateTime.MaxValue` is not a literal field either. – Impworks Mar 07 '13 at 07:25
  • @Impworks In C# the following rules exist: "The _type_ specified in a constant declaration must be `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `char`, `float`, `double`, `decimal`, `bool`, `string`, an _enum-type_, or a _reference-type_." (from the C# Language Specification, §10.4 Constants). Furthermore "the only possible value for constants of _reference-types_ other than `string` is `null`". So those are the C# rules. I guess the .NET rules are similar (they have to allow at least the same constants, of course). – Jeppe Stig Nielsen Mar 07 '13 at 08:26