Skip to content

Commit

Permalink
Add some encoders for records straight through.
Browse files Browse the repository at this point in the history
Fix bootstrap method type.
  • Loading branch information
wasabii committed Aug 1, 2024
1 parent 28d4341 commit b61428d
Show file tree
Hide file tree
Showing 10 changed files with 230 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
namespace IKVM.ByteCode.Parsing
{

public readonly record struct BootstrapMethodsAttributeMethodRecord(MethodHandleConstantHandle MethodRef, ConstantHandle[] Arguments)
public readonly record struct BootstrapMethodsAttributeMethodRecord(MethodHandleConstantHandle Method, ConstantHandle[] Arguments)
{

public static bool TryReadBootstrapMethod(ref ClassFormatReader reader, out BootstrapMethodsAttributeMethodRecord method)
{
method = default;

if (reader.TryReadU2(out ushort methodrefIndex) == false)
if (reader.TryReadU2(out ushort methodIndex) == false)
return false;
if (reader.TryReadU2(out ushort argumentCount) == false)
return false;
Expand All @@ -22,7 +22,7 @@ public static bool TryReadBootstrapMethod(ref ClassFormatReader reader, out Boot
arguments[i] = new(argumentIndex);
}

method = new BootstrapMethodsAttributeMethodRecord(new(methodrefIndex), arguments);
method = new BootstrapMethodsAttributeMethodRecord(new(methodIndex), arguments);
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace IKVM.ByteCode.Reading
public sealed class BootstrapMethodsAttributeMethodReader : ReaderBase<BootstrapMethodsAttributeMethodRecord>
{

MethodrefConstantReader methodref;
MethodHandleConstantReader methodref;
IReadOnlyList<IConstantReader> arguments;

/// <summary>
Expand All @@ -27,7 +27,7 @@ internal BootstrapMethodsAttributeMethodReader(ClassReader declaringClass, Boots
/// <summary>
/// Gets the method being referenced.
/// </summary>
public MethodrefConstantReader Methodref => LazyGet(ref methodref, () => DeclaringClass.Constants.Get<MethodrefConstantReader>(Record.Methodref));
public MethodHandleConstantReader Method => LazyGet(ref methodref, () => DeclaringClass.Constants.Get<MethodrefConstantReader>(Record.MethodRef));

/// <summary>
/// Gets the arguments bound to the method reference.
Expand Down
8 changes: 4 additions & 4 deletions src/IKVM.ByteCode/TypePathKind.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
public enum TypePathKind : byte
{

ArrayType = 0,
NestedType = 1,
ParameterizedWildcardTypeArgument = 2,
ParameterizedType = 3,
Array = 0,
InnerType = 1,
Wildcard = 2,
TypeArgument = 3,

}

Expand Down
10 changes: 9 additions & 1 deletion src/IKVM.ByteCode/Writing/AnnotationEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ public AnnotationEncoder(BlobBuilder builder)
_builder = builder ?? throw new ArgumentNullException(nameof(builder));
}

/// <summary>
/// Encodes an existing annotation.
/// </summary>
/// <param name="annotation"></param>
public void Encode(AnnotationRecord annotation)
{
Encode(annotation.Type, e => e.Encode(annotation.Elements));
}

/// <summary>
/// Encodes a new element_value_pair.
/// </summary>
Expand All @@ -32,7 +41,6 @@ public void Encode(Utf8ConstantHandle type, Action<ElementValuePairTableEncoder>
w.TryWriteU2(type.Index);
elementValuePairs(new ElementValuePairTableEncoder(_builder));
}

}

}
55 changes: 52 additions & 3 deletions src/IKVM.ByteCode/Writing/ElementValueEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,56 @@ public ElementValueEncoder(BlobBuilder builder)
_builder = builder ?? throw new ArgumentNullException(nameof(builder));
}

/// <summary>
/// Encodes an existing element value.
/// </summary>
/// <param name="value"></param>
public void Encode(ElementValueRecord value)
{
switch (value.Tag)
{
case ElementValueTag.Byte:
Byte((IntegerConstantHandle)((ElementValueConstantValueRecord)value.Value).Handle);
break;
case ElementValueTag.Char:
Char((IntegerConstantHandle)((ElementValueConstantValueRecord)value.Value).Handle);
break;
case ElementValueTag.Integer:
Int((IntegerConstantHandle)((ElementValueConstantValueRecord)value.Value).Handle);
break;
case ElementValueTag.Short:
Short((IntegerConstantHandle)((ElementValueConstantValueRecord)value.Value).Handle);
break;
case ElementValueTag.Boolean:
Boolean((IntegerConstantHandle)((ElementValueConstantValueRecord)value.Value).Handle);
break;
case ElementValueTag.Double:
Double((DoubleConstantHandle)((ElementValueConstantValueRecord)value.Value).Handle);
break;
case ElementValueTag.Float:
Float((FloatConstantHandle)((ElementValueConstantValueRecord)value.Value).Handle);
break;
case ElementValueTag.Long:
Long((LongConstantHandle)((ElementValueConstantValueRecord)value.Value).Handle);
break;
case ElementValueTag.String:
String((Utf8ConstantHandle)((ElementValueConstantValueRecord)value.Value).Handle);
break;
case ElementValueTag.Enum:
Enum(((ElementValueEnumConstantValueRecord)value.Value).TypeName, ((ElementValueEnumConstantValueRecord)value.Value).ConstantName);
break;
case ElementValueTag.Class:
Class(((ElementValueClassValueRecord)value.Value).Class);
break;
case ElementValueTag.Annotation:
Annotation(e => e.Encode(((ElementValueAnnotationValueRecord)value.Value).Annotation));
break;
case ElementValueTag.Array:
Array(e => e.Encode(((ElementValueArrayValueRecord)value.Value).Values));
break;
}
}

/// <summary>
/// Constant of the primitive type byte as the value of this element-value pair.
/// </summary>
Expand Down Expand Up @@ -210,17 +260,16 @@ public void Annotation(Action<AnnotationEncoder> annotationValue)
/// Denotes an array as the value of this element-value pair.
/// </summary>
/// <param name="arrayValue"></param>
public void Array(Action<ElementValuePairTableEncoder> arrayValue)
public void Array(Action<ElementValueTableEncoder> arrayValue)
{
if (_count > 0)
throw new InvalidOperationException("Only a single element value can be encoded by this encoder.");

var w = new ClassFormatWriter(_builder.ReserveBytes(ClassFormatWriter.U1).GetBytes());
w.TryWriteU1((byte)ElementValueTag.Array);
arrayValue(new ElementValuePairTableEncoder(_builder));
arrayValue(new ElementValueTableEncoder(_builder));
_count++;
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ public ElementValuePairTableEncoder(BlobBuilder builder)
_count = 0;
}

/// <summary>
/// Encodes an existing set of elements.
/// </summary>
/// <param name="elements"></param>
/// <exception cref="NotImplementedException"></exception>
public void Encode(ReadOnlySpan<ElementValuePairRecord> elements)
{
foreach (var i in elements)
Element(i.Name, e => e.Encode(i.Value));
}

/// <summary>
/// Adds an element value pair.
/// </summary>
Expand Down
56 changes: 56 additions & 0 deletions src/IKVM.ByteCode/Writing/ElementValueTableEncoder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System;

using IKVM.ByteCode.Buffers;
using IKVM.ByteCode.Parsing;

namespace IKVM.ByteCode.Writing
{

/// <summary>
/// Encodes an 'element_value_table' structure.
/// </summary>
public struct ElementValueTableEncoder
{

readonly BlobBuilder _builder;
readonly Blob _countBlob;
ushort _count;

/// <summary>
/// Initializes a new instance.
/// </summary>
/// <param name="constants"></param>
public ElementValueTableEncoder(BlobBuilder builder)
{
_builder = builder ?? throw new ArgumentNullException(nameof(builder));
_countBlob = _builder.ReserveBytes(ClassFormatWriter.U2);
_count = 0;
}

/// <summary>
/// Encodes an existing set of elements.
/// </summary>
/// <param name="elements"></param>
/// <exception cref="NotImplementedException"></exception>
public void Encode(ReadOnlySpan<ElementValueRecord> elements)
{
foreach (var i in elements)
Element(e => e.Encode(i));
}

/// <summary>
/// Adds an element value pair.
/// </summary>
/// <param name="value"></param>
public void Element(Action<ElementValueEncoder> value)
{
if (value is null)
throw new ArgumentNullException(nameof(value));

value(new ElementValueEncoder(_builder));
new ClassFormatWriter(_countBlob.GetBytes()).TryWriteU2(++_count);
}

}

}
43 changes: 43 additions & 0 deletions src/IKVM.ByteCode/Writing/TypeAnnotationEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,49 @@ public TypeAnnotationEncoder(BlobBuilder builder)
_builder = builder ?? throw new ArgumentNullException(nameof(builder));
}

/// <summary>
/// Encodes an existing record.
/// </summary>
/// <param name="record"></param>
public void Encode(TypeAnnotationRecord record)
{
switch (record.Target)
{
case TypeParameterTargetRecord target:
TypeParameterTarget(record.TargetType, target.ParameterIndex, e => e.Encode(record.TargetPath), record.Type, e => e.Encode(record.Elements));
break;
case SuperTypeTargetRecord target:
SuperTypeTarget(record.TargetType, target.SuperTypeIndex, e => e.Encode(record.TargetPath), record.Type, e => e.Encode(record.Elements));
break;
case TypeParameterBoundTargetRecord target:
TypeParameterBoundTarget(record.TargetType, target.ParameterIndex, target.BoundIndex, e => e.Encode(record.TargetPath), record.Type, e => e.Encode(record.Elements));
break;
case EmptyTargetRecord target:
EmptyTarget(record.TargetType, e => e.Encode(record.TargetPath), record.Type, e => e.Encode(record.Elements));
break;
case FormalParameterTargetRecord target:
FormalParameterTarget(record.TargetType, target.ParameterIndex, e => e.Encode(record.TargetPath), record.Type, e => e.Encode(record.Elements));
break;
case ThrowsTargetRecord target:
ThrowsTarget(record.TargetType, target.ThrowsTypeIndex, e => e.Encode(record.TargetPath), record.Type, e => e.Encode(record.Elements));
break;
case LocalVariableTargetTableRecord target:
LocalVarTarget(record.TargetType, e => e.Encode(target), record.Type, e => e.Encode(record.Elements));
break;
case CatchTargetRecord target:
CatchTarget(record.TargetType, target.ExceptionTableIndex, e => e.Encode(record.TargetPath), record.Type, e => e.Encode(record.Elements));
break;
case OffsetTargetRecord target:
OffsetTarget(record.TargetType, target.Offset, e => e.Encode(record.TargetPath), record.Type, e => e.Encode(record.Elements));
break;
case TypeArgumentTargetRecord target:
TypeArgumentTarget(record.TargetType, target.Offset, target.TypeArgumentIndex, e => e.Encode(record.TargetPath), record.Type, e => e.Encode(record.Elements));
break;
default:
throw new InvalidOperationException("Invalid type annotation.");
}
}

/// <summary>
/// Encodes the footer of the structure.
/// </summary>
Expand Down
15 changes: 15 additions & 0 deletions src/IKVM.ByteCode/Writing/TypeAnnotationTableEncoder.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Security.Policy;

using IKVM.ByteCode.Buffers;
using IKVM.ByteCode.Parsing;
Expand Down Expand Up @@ -38,6 +39,20 @@ public TypeAnnotationTableEncoder Add(Action<TypeAnnotationEncoder> annotation)
return this;
}

/// <summary>
/// Adds an annotation.
/// </summary>
/// <param name="record"></param>
/// <returns></returns>
public TypeAnnotationTableEncoder Add(TypeAnnotationRecord record)
{
return Add(encoder => Add(encoder, record));
}

static void Add(TypeAnnotationEncoder encoder, TypeAnnotationRecord record)
{
}

}

}
38 changes: 35 additions & 3 deletions src/IKVM.ByteCode/Writing/TypePathEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,43 @@ public TypePathEncoder(BlobBuilder builder)
_count = 0;
}

/// <summary>
/// Encodes an existing type path.
/// </summary>
/// <param name="targetPath"></param>
public void Encode(TypePathRecord targetPath)
{
foreach (var i in targetPath.Path)
Encode(i);
}

/// <summary>
/// Encodes an existing type path item.
/// </summary>
/// <param name="item"></param>
public void Encode(TypePathItemRecord item)
{
switch (item.Kind)
{
case TypePathKind.Array:
Array();
break;
case TypePathKind.InnerType:
InnerType();
break;
case TypePathKind.Wildcard:
Wildcard();
break;
case TypePathKind.TypeArgument:
TypeArgument(item.ArgumentIndex);
break;
}
}

/// <summary>
/// Annotation is deeper in an array type.
/// </summary>
public void ArrayElement()
public void Array()
{
var w = new ClassFormatWriter(_builder.ReserveBytes(ClassFormatWriter.U1 + ClassFormatWriter.U1).GetBytes());
w.TryWriteU1(0);
Expand All @@ -49,7 +82,7 @@ public void InnerType()
/// <summary>
/// Annotation is on the bound of a wildcard type argument of a parameterized type.
/// </summary>
public void WildcardBound()
public void Wildcard()
{
var w = new ClassFormatWriter(_builder.ReserveBytes(ClassFormatWriter.U1 + ClassFormatWriter.U1).GetBytes());
w.TryWriteU1(2);
Expand All @@ -67,7 +100,6 @@ public void TypeArgument(byte index)
w.TryWriteU1(index);
new ClassFormatWriter(_countBlob.GetBytes()).TryWriteU1(++_count);
}

}

}

0 comments on commit b61428d

Please sign in to comment.