158 lines
4.9 KiB
C#
158 lines
4.9 KiB
C#
|
|
using System.Text;
|
||
|
|
|
||
|
|
namespace JCIL.Java.Class;
|
||
|
|
|
||
|
|
public enum ConstantType
|
||
|
|
{
|
||
|
|
Class = 7,
|
||
|
|
FieldRef = 9,
|
||
|
|
MethodRef = 10,
|
||
|
|
InterfaceMethodRef = 11,
|
||
|
|
String = 8,
|
||
|
|
Integer = 3,
|
||
|
|
Float = 4,
|
||
|
|
Long = 5,
|
||
|
|
Double = 6,
|
||
|
|
NameAndType = 12,
|
||
|
|
Utf8 = 1,
|
||
|
|
MethodHandle = 15,
|
||
|
|
MethodType = 16,
|
||
|
|
InvokeDynamic = 18,
|
||
|
|
}
|
||
|
|
|
||
|
|
public sealed record NameAndType(string Name, string Descriptor);
|
||
|
|
|
||
|
|
public sealed record MethodRef(Class Class, NameAndType Method);
|
||
|
|
public sealed record FieldRef(Class Class, NameAndType Field);
|
||
|
|
|
||
|
|
public record struct Constant(ConstantType Type, object Value)
|
||
|
|
{
|
||
|
|
public static Constant Read(Class self, TypeLoader loader, Reader reader)
|
||
|
|
{
|
||
|
|
object value;
|
||
|
|
var type = (ConstantType)reader.ReadUInt8();
|
||
|
|
switch (type)
|
||
|
|
{
|
||
|
|
|
||
|
|
case ConstantType.Class:
|
||
|
|
case ConstantType.String:
|
||
|
|
case ConstantType.MethodType:
|
||
|
|
{
|
||
|
|
value = reader.ReadUInt16();
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case ConstantType.Integer:
|
||
|
|
{
|
||
|
|
value = reader.ReadInt32();
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case ConstantType.Float:
|
||
|
|
{
|
||
|
|
value = reader.ReadFloat();
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case ConstantType.Long:
|
||
|
|
{
|
||
|
|
value = reader.ReadInt64();
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case ConstantType.Double:
|
||
|
|
{
|
||
|
|
value = reader.ReadDouble();
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case ConstantType.FieldRef:
|
||
|
|
case ConstantType.MethodRef:
|
||
|
|
case ConstantType.NameAndType:
|
||
|
|
case ConstantType.InvokeDynamic:
|
||
|
|
case ConstantType.InterfaceMethodRef:
|
||
|
|
{
|
||
|
|
value = (reader.ReadUInt16(), reader.ReadUInt16());
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case ConstantType.Utf8:
|
||
|
|
{
|
||
|
|
var length = reader.ReadUInt16();
|
||
|
|
var buffer = new byte[length];
|
||
|
|
reader.Stream.ReadExactly(buffer);
|
||
|
|
value = Encoding.UTF8.GetString(buffer);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case ConstantType.MethodHandle:
|
||
|
|
{
|
||
|
|
value = (reader.ReadUInt8(), reader.ReadUInt16());
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
default:
|
||
|
|
{
|
||
|
|
value = null!;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return new Constant(type, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
public static object? Resolve(TypeLoader loader, Constant[] constants, ushort i)
|
||
|
|
{
|
||
|
|
if (i == 0 || i > constants.Length) return null;
|
||
|
|
i -= 1;
|
||
|
|
switch (constants[i])
|
||
|
|
{
|
||
|
|
case { Type: ConstantType.Class, Value: ushort index }:
|
||
|
|
{
|
||
|
|
var name = (string) Resolve(loader, constants, index)!;
|
||
|
|
constants[i] = new Constant(ConstantType.Class, loader.GetClass(name.AsMemory()));
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case { Type: ConstantType.MethodRef, Value: (ushort classIndex, ushort nameTypeIndex) }:
|
||
|
|
{
|
||
|
|
var name = (Class)Resolve(loader, constants, classIndex)!;
|
||
|
|
var descriptor = (NameAndType)Resolve(loader, constants, nameTypeIndex)!;
|
||
|
|
constants[i] = new Constant(ConstantType.MethodRef, new MethodRef(name, descriptor));
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case { Type: ConstantType.FieldRef, Value: (ushort classIndex, ushort nameTypeIndex) }:
|
||
|
|
{
|
||
|
|
var name = (Class)Resolve(loader, constants, classIndex)!;
|
||
|
|
var descriptor = (NameAndType)Resolve(loader, constants, nameTypeIndex)!;
|
||
|
|
constants[i] = new Constant(ConstantType.FieldRef, new FieldRef(name, descriptor));
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case { Type: ConstantType.InterfaceMethodRef, Value: (ushort classIndex, ushort nameTypeIndex) }:
|
||
|
|
{
|
||
|
|
var name = (Class)Resolve(loader, constants, classIndex)!;
|
||
|
|
var descriptor = (NameAndType)Resolve(loader, constants, nameTypeIndex)!;
|
||
|
|
constants[i] = new Constant(ConstantType.InterfaceMethodRef, new MethodRef(name, descriptor));
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case { Type: ConstantType.String, Value: ushort index }:
|
||
|
|
{
|
||
|
|
var text = (string)Resolve(loader, constants, index)!;
|
||
|
|
constants[i] = new Constant(ConstantType.String, text);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case { Type: ConstantType.NameAndType, Value: (ushort nameIndex, ushort descriptorIndex) }:
|
||
|
|
{
|
||
|
|
var name = (string)Resolve(loader, constants, nameIndex)!;
|
||
|
|
var descriptor = (string)Resolve(loader, constants, descriptorIndex)!;
|
||
|
|
constants[i] = new Constant(ConstantType.NameAndType, new NameAndType(name, descriptor));
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return constants[i].Value;
|
||
|
|
}
|
||
|
|
}
|