diff --git a/IK.VM.NET/CodeEmitter.cs b/IK.VM.NET/CodeEmitter.cs index 5440468e..4ebd7e55 100644 --- a/IK.VM.NET/CodeEmitter.cs +++ b/IK.VM.NET/CodeEmitter.cs @@ -141,9 +141,58 @@ public abstract class CodeEmitter internal static CodeEmitter Create(OpCode opcode, FieldInfo fi) { Debug.Assert(fi != null); + Debug.Assert(!fi.IsLiteral); return new FieldInfoCodeEmitter(opcode, fi); } + internal static CodeEmitter CreateLoadConstant(object constant) + { + if(constant == null) + { + return new CodeEmitter.OpCodeEmitter(OpCodes.Ldnull); + } + else if(constant is int || constant is uint || + constant is short || constant is ushort || + constant is byte || constant is sbyte || + constant is char || + constant is bool) + { + return CodeEmitter.Create(OpCodes.Ldc_I4, ((IConvertible)constant).ToInt32(null)); + } + else if(constant is string) + { + return CodeEmitter.Create(OpCodes.Ldstr, (string)constant); + } + else if(constant is float) + { + return CodeEmitter.Create(OpCodes.Ldc_R4, (float)constant); + } + else if(constant is double) + { + return CodeEmitter.Create(OpCodes.Ldc_R8, (double)constant); + } + else if(constant is long || constant is ulong) + { + return CodeEmitter.Create(OpCodes.Ldc_I8, (long)constant); + } + else if(constant is Enum) + { + Type underlying = Enum.GetUnderlyingType(constant.GetType()); + if(underlying == typeof(long) || underlying == typeof(ulong)) + { + return CodeEmitter.Create(OpCodes.Ldc_I8, ((IConvertible)constant).ToInt64(null)); + } + else + { + return CodeEmitter.Create(OpCodes.Ldc_I4, ((IConvertible)constant).ToInt32(null)); + } + } + else + { + throw new NotImplementedException(constant.GetType().FullName); + } + } + private class OpCodeEmitter : CodeEmitter { private OpCode opcode; diff --git a/IK.VM.NET/TypeWrapper.cs b/IK.VM.NET/TypeWrapper.cs index 3fe5db88..2f1295f1 100644 --- a/IK.VM.NET/TypeWrapper.cs +++ b/IK.VM.NET/TypeWrapper.cs @@ -1935,30 +1935,7 @@ class DynamicTypeWrapper : TypeWrapper // NOTE even though you're not supposed to access a constant static final (the compiler is supposed // to inline them), we have to support it (because it does happen, e.g. if the field becomes final // after the referencing class was compiled) - if(constantValue is int || constantValue is short || constantValue is sbyte || constantValue is char || constantValue is bool) - { - fields[i].EmitGet = CodeEmitter.Create(OpCodes.Ldc_I4, ((IConvertible)constantValue).ToInt32(null)); - } - else if(constantValue is string) - { - fields[i].EmitGet = CodeEmitter.Create(OpCodes.Ldstr, (string)constantValue); - } - else if(constantValue is float) - { - fields[i].EmitGet = CodeEmitter.Create(OpCodes.Ldc_R4, (float)constantValue); - } - else if(constantValue is double) - { - fields[i].EmitGet = CodeEmitter.Create(OpCodes.Ldc_R8, (double)constantValue); - } - else if(constantValue is long) - { - fields[i].EmitGet = CodeEmitter.Create(OpCodes.Ldc_I8, (long)constantValue); - } - else - { - throw new NotImplementedException(constantValue.GetType().FullName); - } + fields[i].EmitGet = CodeEmitter.CreateLoadConstant(constantValue); // when non-blank final fields are updated, the JIT normally doesn't see that (because the // constant value is inlined), so we emulate that behavior by emitting a Pop fields[i].EmitSet = CodeEmitter.Pop; @@ -2142,7 +2119,9 @@ class DynamicTypeWrapper : TypeWrapper { // NOTE we don't need to record the modifiers here, because they aren't visible from Java reflection // (well they might be visible from JNI reflection, but that isn't important enough to justify the custom attribute) - method = typeBuilder.DefineTypeInitializer(); + // HACK because Peverify (in Whidbey) is complaining about private methods in interfaces, I'm making them public for the time being + method = typeBuilder.DefineConstructor(MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes); + //method = typeBuilder.DefineTypeInitializer(); } else { @@ -3497,10 +3476,17 @@ class CompiledTypeWrapper : TypeWrapper } else { - // TODO if field is a literal, we should emit an ldc instead of a ldsfld - fieldWrapper.EmitGet = CodeEmitter.Create(OpCodes.Ldsfld, field); + // if field is a literal, we emit an ldc instead of a ldsfld + if(field.IsLiteral) + { + fieldWrapper.EmitGet = CodeEmitter.CreateLoadConstant(field.GetValue(null)); + } + else + { + fieldWrapper.EmitGet = CodeEmitter.Create(OpCodes.Ldsfld, field); + } } - if(field != null) + if(field != null && !field.IsLiteral) { fieldWrapper.EmitSet = CodeEmitter.Create(OpCodes.Stsfld, field); }