diff --git a/JavaAsm/AttributeNode.cs b/JavaAsm/AttributeNode.cs index 7dee115..16ac9ec 100644 --- a/JavaAsm/AttributeNode.cs +++ b/JavaAsm/AttributeNode.cs @@ -6,10 +6,8 @@ using JavaAsm.Helpers; using JavaAsm.IO; -namespace JavaAsm -{ - public static class PredefinedAttributeNames - { +namespace JavaAsm { + public static class PredefinedAttributeNames { public const string AnnotationDefault = "AnnotationDefault"; public const string BootstrapMethods = "BootstrapMethods"; public const string Code = "Code"; @@ -35,50 +33,48 @@ public static class PredefinedAttributeNames public const string Synthetic = "Synthetic"; } - public class AttributeNode - { + public class AttributeNode { private static readonly Dictionary<(string Name, AttributeScope Scope), ICustomAttributeFactory> predefinedAttributes - = new Dictionary<(string Name, AttributeScope Scope), ICustomAttributeFactory> - { - { (PredefinedAttributeNames.Code, AttributeScope.Method), new CodeAttributeFactory() }, - { (PredefinedAttributeNames.ConstantValue, AttributeScope.Field), new ConstantValueAttributeFactory() }, - { (PredefinedAttributeNames.SourceDebugExtension, AttributeScope.Class), new SourceDebugExtensionFactory() }, - { (PredefinedAttributeNames.SourceFile, AttributeScope.Class), new SourceFileAttributeFactory() }, - { (PredefinedAttributeNames.Exceptions, AttributeScope.Method), new ExceptionsAttributeFactory() }, - { (PredefinedAttributeNames.EnclosingMethod, AttributeScope.Class), new EnclosingMethodAttributeFactory() }, - { (PredefinedAttributeNames.Synthetic, AttributeScope.Class), new SyntheticAttributeFactory() }, - { (PredefinedAttributeNames.Synthetic, AttributeScope.Method), new SyntheticAttributeFactory() }, - { (PredefinedAttributeNames.Synthetic, AttributeScope.Field), new SyntheticAttributeFactory() }, - { (PredefinedAttributeNames.Signature, AttributeScope.Class), new SignatureAttributeFactory() }, - { (PredefinedAttributeNames.Signature, AttributeScope.Method), new SignatureAttributeFactory() }, - { (PredefinedAttributeNames.Signature, AttributeScope.Field), new SignatureAttributeFactory() }, - { (PredefinedAttributeNames.LineNumberTable, AttributeScope.Code), new LineNumberTableAttributeFactory() }, - { (PredefinedAttributeNames.Deprecated, AttributeScope.Class), new DeprecatedAttributeFactory() }, - { (PredefinedAttributeNames.Deprecated, AttributeScope.Method), new DeprecatedAttributeFactory() }, - { (PredefinedAttributeNames.Deprecated, AttributeScope.Field), new DeprecatedAttributeFactory() }, - { (PredefinedAttributeNames.MethodParameters, AttributeScope.Method), new MethodParametersAttributeFactory() }, - { (PredefinedAttributeNames.LocalVariableTable, AttributeScope.Code), new LocalVariableTableAttributeFactory() }, - { (PredefinedAttributeNames.LocalVariableTypeTable, AttributeScope.Code), new LocalVariableTypeTableAttributeFactory() }, - { (PredefinedAttributeNames.InnerClasses, AttributeScope.Class), new InnerClassesAttributeFactory() }, - { (PredefinedAttributeNames.RuntimeInvisibleAnnotations, AttributeScope.Class), new RuntimeInvisibleAnnotationsAttributeFactory() }, - { (PredefinedAttributeNames.RuntimeInvisibleAnnotations, AttributeScope.Method), new RuntimeInvisibleAnnotationsAttributeFactory() }, - { (PredefinedAttributeNames.RuntimeInvisibleAnnotations, AttributeScope.Field), new RuntimeInvisibleAnnotationsAttributeFactory() }, - { (PredefinedAttributeNames.RuntimeVisibleAnnotations, AttributeScope.Class), new RuntimeVisibleAnnotationsAttributeFactory() }, - { (PredefinedAttributeNames.RuntimeVisibleAnnotations, AttributeScope.Method), new RuntimeVisibleAnnotationsAttributeFactory() }, - { (PredefinedAttributeNames.RuntimeVisibleAnnotations, AttributeScope.Field), new RuntimeVisibleAnnotationsAttributeFactory() }, - { (PredefinedAttributeNames.RuntimeInvisibleParameterAnnotations, AttributeScope.Method), new RuntimeInvisibleParameterAnnotationsAttributeFactory() }, - { (PredefinedAttributeNames.RuntimeVisibleParameterAnnotations, AttributeScope.Method), new RuntimeVisibleParameterAnnotationsAttributeFactory() }, - { (PredefinedAttributeNames.RuntimeInvisibleTypeAnnotations, AttributeScope.Class), new RuntimeInvisibleTypeAnnotationsAttributeFactory() }, - { (PredefinedAttributeNames.RuntimeInvisibleTypeAnnotations, AttributeScope.Method), new RuntimeInvisibleTypeAnnotationsAttributeFactory() }, - { (PredefinedAttributeNames.RuntimeInvisibleTypeAnnotations, AttributeScope.Field), new RuntimeInvisibleTypeAnnotationsAttributeFactory() }, - { (PredefinedAttributeNames.RuntimeInvisibleTypeAnnotations, AttributeScope.Code), new RuntimeInvisibleTypeAnnotationsAttributeFactory() }, - { (PredefinedAttributeNames.RuntimeVisibleTypeAnnotations, AttributeScope.Class), new RuntimeVisibleTypeAnnotationsAttributeFactory() }, - { (PredefinedAttributeNames.RuntimeVisibleTypeAnnotations, AttributeScope.Method), new RuntimeVisibleTypeAnnotationsAttributeFactory() }, - { (PredefinedAttributeNames.RuntimeVisibleTypeAnnotations, AttributeScope.Field), new RuntimeVisibleTypeAnnotationsAttributeFactory() }, - { (PredefinedAttributeNames.RuntimeVisibleTypeAnnotations, AttributeScope.Code), new RuntimeVisibleTypeAnnotationsAttributeFactory() }, - { (PredefinedAttributeNames.AnnotationDefault, AttributeScope.Method), new AnnotationDefaultAttributeFactory() }, - { (PredefinedAttributeNames.BootstrapMethods, AttributeScope.Class), new BootstrapMethodsAttributeFactory() }, - { (PredefinedAttributeNames.StackMapTable, AttributeScope.Code), new StackMapTableAttributeFactory() } + = new Dictionary<(string Name, AttributeScope Scope), ICustomAttributeFactory> { + {(PredefinedAttributeNames.Code, AttributeScope.Method), new CodeAttributeFactory()}, + {(PredefinedAttributeNames.ConstantValue, AttributeScope.Field), new ConstantValueAttributeFactory()}, + {(PredefinedAttributeNames.SourceDebugExtension, AttributeScope.Class), new SourceDebugExtensionFactory()}, + {(PredefinedAttributeNames.SourceFile, AttributeScope.Class), new SourceFileAttributeFactory()}, + {(PredefinedAttributeNames.Exceptions, AttributeScope.Method), new ExceptionsAttributeFactory()}, + {(PredefinedAttributeNames.EnclosingMethod, AttributeScope.Class), new EnclosingMethodAttributeFactory()}, + {(PredefinedAttributeNames.Synthetic, AttributeScope.Class), new SyntheticAttributeFactory()}, + {(PredefinedAttributeNames.Synthetic, AttributeScope.Method), new SyntheticAttributeFactory()}, + {(PredefinedAttributeNames.Synthetic, AttributeScope.Field), new SyntheticAttributeFactory()}, + {(PredefinedAttributeNames.Signature, AttributeScope.Class), new SignatureAttributeFactory()}, + {(PredefinedAttributeNames.Signature, AttributeScope.Method), new SignatureAttributeFactory()}, + {(PredefinedAttributeNames.Signature, AttributeScope.Field), new SignatureAttributeFactory()}, + {(PredefinedAttributeNames.LineNumberTable, AttributeScope.Code), new LineNumberTableAttributeFactory()}, + {(PredefinedAttributeNames.Deprecated, AttributeScope.Class), new DeprecatedAttributeFactory()}, + {(PredefinedAttributeNames.Deprecated, AttributeScope.Method), new DeprecatedAttributeFactory()}, + {(PredefinedAttributeNames.Deprecated, AttributeScope.Field), new DeprecatedAttributeFactory()}, + {(PredefinedAttributeNames.MethodParameters, AttributeScope.Method), new MethodParametersAttributeFactory()}, + {(PredefinedAttributeNames.LocalVariableTable, AttributeScope.Code), new LocalVariableTableAttributeFactory()}, + {(PredefinedAttributeNames.LocalVariableTypeTable, AttributeScope.Code), new LocalVariableTypeTableAttributeFactory()}, + {(PredefinedAttributeNames.InnerClasses, AttributeScope.Class), new InnerClassesAttributeFactory()}, + {(PredefinedAttributeNames.RuntimeInvisibleAnnotations, AttributeScope.Class), new RuntimeInvisibleAnnotationsAttributeFactory()}, + {(PredefinedAttributeNames.RuntimeInvisibleAnnotations, AttributeScope.Method), new RuntimeInvisibleAnnotationsAttributeFactory()}, + {(PredefinedAttributeNames.RuntimeInvisibleAnnotations, AttributeScope.Field), new RuntimeInvisibleAnnotationsAttributeFactory()}, + {(PredefinedAttributeNames.RuntimeVisibleAnnotations, AttributeScope.Class), new RuntimeVisibleAnnotationsAttributeFactory()}, + {(PredefinedAttributeNames.RuntimeVisibleAnnotations, AttributeScope.Method), new RuntimeVisibleAnnotationsAttributeFactory()}, + {(PredefinedAttributeNames.RuntimeVisibleAnnotations, AttributeScope.Field), new RuntimeVisibleAnnotationsAttributeFactory()}, + {(PredefinedAttributeNames.RuntimeInvisibleParameterAnnotations, AttributeScope.Method), new RuntimeInvisibleParameterAnnotationsAttributeFactory()}, + {(PredefinedAttributeNames.RuntimeVisibleParameterAnnotations, AttributeScope.Method), new RuntimeVisibleParameterAnnotationsAttributeFactory()}, + {(PredefinedAttributeNames.RuntimeInvisibleTypeAnnotations, AttributeScope.Class), new RuntimeInvisibleTypeAnnotationsAttributeFactory()}, + {(PredefinedAttributeNames.RuntimeInvisibleTypeAnnotations, AttributeScope.Method), new RuntimeInvisibleTypeAnnotationsAttributeFactory()}, + {(PredefinedAttributeNames.RuntimeInvisibleTypeAnnotations, AttributeScope.Field), new RuntimeInvisibleTypeAnnotationsAttributeFactory()}, + {(PredefinedAttributeNames.RuntimeInvisibleTypeAnnotations, AttributeScope.Code), new RuntimeInvisibleTypeAnnotationsAttributeFactory()}, + {(PredefinedAttributeNames.RuntimeVisibleTypeAnnotations, AttributeScope.Class), new RuntimeVisibleTypeAnnotationsAttributeFactory()}, + {(PredefinedAttributeNames.RuntimeVisibleTypeAnnotations, AttributeScope.Method), new RuntimeVisibleTypeAnnotationsAttributeFactory()}, + {(PredefinedAttributeNames.RuntimeVisibleTypeAnnotations, AttributeScope.Field), new RuntimeVisibleTypeAnnotationsAttributeFactory()}, + {(PredefinedAttributeNames.RuntimeVisibleTypeAnnotations, AttributeScope.Code), new RuntimeVisibleTypeAnnotationsAttributeFactory()}, + {(PredefinedAttributeNames.AnnotationDefault, AttributeScope.Method), new AnnotationDefaultAttributeFactory()}, + {(PredefinedAttributeNames.BootstrapMethods, AttributeScope.Class), new BootstrapMethodsAttributeFactory()}, + {(PredefinedAttributeNames.StackMapTable, AttributeScope.Code), new StackMapTableAttributeFactory()} }; public string Name { get; set; } @@ -87,41 +83,34 @@ public class AttributeNode public CustomAttribute ParsedAttribute { get; set; } - internal void Parse(Stream stream, AttributeScope scope, ClassReaderState readerState) - { - var dataLength = Binary.BigEndian.ReadUInt32(stream); - var data = stream.ReadBytes(dataLength); + internal void Parse(Stream stream, AttributeScope scope, ClassReaderState readerState) { + uint dataLength = Binary.BigEndian.ReadUInt32(stream); + byte[] data = stream.ReadBytes(dataLength); - try - { - if (!predefinedAttributes.ContainsKey((Name, scope))) - throw new ArgumentException($"Attribute {Name} in {scope} not found"); - var readWriteCounter = new ReadWriteCountStream(new MemoryStream(data)); - ParsedAttribute = predefinedAttributes[(Name, scope)].Parse(readWriteCounter, dataLength, readerState, scope); + try { + if (!predefinedAttributes.ContainsKey((this.Name, scope))) + throw new ArgumentException($"Attribute {this.Name} in {scope} not found"); + ReadWriteCountStream readWriteCounter = new ReadWriteCountStream(new MemoryStream(data)); + this.ParsedAttribute = predefinedAttributes[(this.Name, scope)].Parse(readWriteCounter, dataLength, readerState, scope); if (readWriteCounter.ReadBytes != dataLength) throw new ArgumentOutOfRangeException(nameof(dataLength), - $"Wrong data length of attribute {Name} in {scope}: Given {dataLength}, Read: {readWriteCounter.ReadBytes}"); - } - catch - { - Data = data; + $"Wrong data length of attribute {this.Name} in {scope}: Given {dataLength}, Read: {readWriteCounter.ReadBytes}"); + } + catch { + this.Data = data; } - } } - public abstract class CustomAttribute - { + public abstract class CustomAttribute { internal abstract byte[] Save(ClassWriterState writerState, AttributeScope scope); } - internal interface ICustomAttributeFactory where T : CustomAttribute - { + internal interface ICustomAttributeFactory where T : CustomAttribute { T Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope); } - internal enum AttributeScope - { + internal enum AttributeScope { Class, Method, Field, diff --git a/JavaAsm/ClassAccessModifiers.cs b/JavaAsm/ClassAccessModifiers.cs index 745606d..e02714a 100644 --- a/JavaAsm/ClassAccessModifiers.cs +++ b/JavaAsm/ClassAccessModifiers.cs @@ -1,11 +1,9 @@ using System; using System.Linq; -namespace JavaAsm -{ +namespace JavaAsm { [Flags] - public enum ClassAccessModifiers : ushort - { + public enum ClassAccessModifiers : ushort { Public = 0x0001, Protected = 0x0004, Private = 0x0002, @@ -21,8 +19,7 @@ public enum ClassAccessModifiers : ushort } [Flags] - public enum MethodAccessModifiers : ushort - { + public enum MethodAccessModifiers : ushort { Public = 0x0001, Protected = 0x0004, Private = 0x0002, @@ -38,8 +35,7 @@ public enum MethodAccessModifiers : ushort } [Flags] - public enum FieldAccessModifiers : ushort - { + public enum FieldAccessModifiers : ushort { Public = 0x0001, Protected = 0x0004, Private = 0x0002, @@ -51,26 +47,10 @@ public enum FieldAccessModifiers : ushort } public static class AccessModifiersExtensions { + public static string ToString(ClassAccessModifiers accessModifiers) => string.Join(" ", Enum.GetValues(typeof(ClassAccessModifiers)).OfType().Where(x => accessModifiers.HasFlag(x)).Select(x => x.ToString().ToLower())); - public static string ToString(ClassAccessModifiers accessModifiers) - { - return string.Join(' ', - Enum.GetValues(typeof(ClassAccessModifiers)).OfType().Where(x => accessModifiers.HasFlag(x)) - .Select(x => x.ToString().ToLower())); - } + public static string ToString(MethodAccessModifiers accessModifiers) => string.Join(" ", Enum.GetValues(typeof(MethodAccessModifiers)).OfType().Where(x => accessModifiers.HasFlag(x)).Select(x => x.ToString().ToLower())); - public static string ToString(MethodAccessModifiers accessModifiers) - { - return string.Join(' ', - Enum.GetValues(typeof(MethodAccessModifiers)).OfType().Where(x => accessModifiers.HasFlag(x)) - .Select(x => x.ToString().ToLower())); - } - - public static string ToString(FieldAccessModifiers accessModifiers) - { - return string.Join(' ', - Enum.GetValues(typeof(FieldAccessModifiers)).OfType().Where(x => accessModifiers.HasFlag(x)) - .Select(x => x.ToString().ToLower())); - } + public static string ToString(FieldAccessModifiers accessModifiers) => string.Join(" ", Enum.GetValues(typeof(FieldAccessModifiers)).OfType().Where(x => accessModifiers.HasFlag(x)).Select(x => x.ToString().ToLower())); } } \ No newline at end of file diff --git a/JavaAsm/ClassName.cs b/JavaAsm/ClassName.cs index 35be692..77fc258 100644 --- a/JavaAsm/ClassName.cs +++ b/JavaAsm/ClassName.cs @@ -1,36 +1,54 @@ using System; +using System.Windows.Input; -namespace JavaAsm -{ - public class ClassName - { +namespace JavaAsm { + /// + /// The name of a class, where the separator for packages and the class name is the / char (e.g java/lang/String) + /// + public class ClassName { public string Name { get; } - public ClassName(string name) - { - Name = name ?? throw new ArgumentNullException(nameof(name)); + public ClassName(string name) { + this.Name = name ?? throw new ArgumentNullException(nameof(name)); } - public override string ToString() - { - return Name.Replace("/", "."); + public static bool TryParse(string value, out ClassName name) { + if (string.IsNullOrEmpty(value)) { + name = null; + return false; + } + + // convert type descriptor to class name + if (value[0] == 'L' && value[value.Length - 1] == ';') { + value = value.Substring(1, value.Length - 2); + } + + name = new ClassName(value.Replace('.', '/')); + return true; + } + + public override string ToString() { + return this.Name.Replace('/', '.'); } - private bool Equals(ClassName other) - { - return Name == other.Name; + private bool Equals(ClassName other) { + return this.Name == other.Name; } - public override bool Equals(object obj) - { - if (obj is null) return false; - if (ReferenceEquals(this, obj)) return true; + public override bool Equals(object obj) { + if (obj is null) + return false; + if (ReferenceEquals(this, obj)) + return true; return obj.GetType() == GetType() && Equals((ClassName) obj); } - public override int GetHashCode() - { - return Name.GetHashCode(); + public override int GetHashCode() { + return this.Name.GetHashCode(); + } + + public ClassName Copy() { + return new ClassName(this.Name); } } } \ No newline at end of file diff --git a/JavaAsm/ClassNode.cs b/JavaAsm/ClassNode.cs index b0b892c..81a9d3e 100644 --- a/JavaAsm/ClassNode.cs +++ b/JavaAsm/ClassNode.cs @@ -5,13 +5,11 @@ using JavaAsm.CustomAttributes.Annotation; using JavaAsm.IO; -namespace JavaAsm -{ +namespace JavaAsm { /// /// Class node /// - public class ClassNode - { + public class ClassNode { public ClassVersion MajorVersion { get; set; } public ushort MinorVersion { get; set; } @@ -47,170 +45,136 @@ public class ClassNode public List InnerClasses { get; set; } = new List(); - private AttributeNode GetAttribute(string name) - { - var attribute = Attributes.FirstOrDefault(a => a.Name == name); + private AttributeNode GetAttribute(string name) { + AttributeNode attribute = this.Attributes.FirstOrDefault(a => a.Name == name); if (attribute != null) - Attributes.Remove(attribute); + this.Attributes.Remove(attribute); return attribute; } - internal void Parse(ClassReaderState readerState) - { - SourceFile = (GetAttribute(PredefinedAttributeNames.SourceFile)?.ParsedAttribute as SourceFileAttribute)?.Value; - SourceDebugExtension = (GetAttribute(PredefinedAttributeNames.SourceDebugExtension)?.ParsedAttribute as SourceFileAttribute)?.Value; - Signature = (GetAttribute(PredefinedAttributeNames.Signature)?.ParsedAttribute as SignatureAttribute)?.Value; + internal void Parse(ClassReaderState readerState) { + this.SourceFile = (GetAttribute(PredefinedAttributeNames.SourceFile)?.ParsedAttribute as SourceFileAttribute)?.Value; + this.SourceDebugExtension = (GetAttribute(PredefinedAttributeNames.SourceDebugExtension)?.ParsedAttribute as SourceFileAttribute)?.Value; + this.Signature = (GetAttribute(PredefinedAttributeNames.Signature)?.ParsedAttribute as SignatureAttribute)?.Value; { - var attribute = GetAttribute(PredefinedAttributeNames.RuntimeInvisibleAnnotations); + AttributeNode attribute = GetAttribute(PredefinedAttributeNames.RuntimeInvisibleAnnotations); if (attribute != null) - InvisibleAnnotations = (attribute.ParsedAttribute as RuntimeInvisibleAnnotationsAttribute)?.Annotations; + this.InvisibleAnnotations = (attribute.ParsedAttribute as RuntimeInvisibleAnnotationsAttribute)?.Annotations; } { - var attribute = GetAttribute(PredefinedAttributeNames.RuntimeVisibleAnnotations); + AttributeNode attribute = GetAttribute(PredefinedAttributeNames.RuntimeVisibleAnnotations); if (attribute != null) - VisibleAnnotations = (attribute.ParsedAttribute as RuntimeVisibleAnnotationsAttribute)?.Annotations; + this.VisibleAnnotations = (attribute.ParsedAttribute as RuntimeVisibleAnnotationsAttribute)?.Annotations; } - IsDeprecated = GetAttribute(PredefinedAttributeNames.Deprecated)?.ParsedAttribute != null; - EnclosingMethod = GetAttribute(PredefinedAttributeNames.EnclosingMethod)?.ParsedAttribute as EnclosingMethodAttribute; + this.IsDeprecated = GetAttribute(PredefinedAttributeNames.Deprecated)?.ParsedAttribute != null; + this.EnclosingMethod = GetAttribute(PredefinedAttributeNames.EnclosingMethod)?.ParsedAttribute as EnclosingMethodAttribute; { - var attribute = GetAttribute(PredefinedAttributeNames.InnerClasses); + AttributeNode attribute = GetAttribute(PredefinedAttributeNames.InnerClasses); if (attribute != null) - InnerClasses = (attribute.ParsedAttribute as InnerClassesAttribute)?.Classes; + this.InnerClasses = (attribute.ParsedAttribute as InnerClassesAttribute)?.Classes; } - foreach (var method in Methods) + foreach (MethodNode method in this.Methods) method.Parse(readerState); - foreach (var field in Fields) + foreach (FieldNode field in this.Fields) field.Parse(readerState); } - internal void Save(ClassWriterState writerState) - { - if (SourceFile != null) - { - if (Attributes.Any(x => x.Name == PredefinedAttributeNames.SourceFile)) - throw new Exception( - $"{PredefinedAttributeNames.SourceFile} attribute is already presented on field"); - Attributes.Add(new AttributeNode - { + internal void Save(ClassWriterState writerState) { + if (this.SourceFile != null) { + if (this.Attributes.Any(x => x.Name == PredefinedAttributeNames.SourceFile)) + throw new Exception($"{PredefinedAttributeNames.SourceFile} attribute is already presented on field"); + this.Attributes.Add(new AttributeNode { Name = PredefinedAttributeNames.SourceFile, - ParsedAttribute = new SourceFileAttribute - { - Value = SourceFile + ParsedAttribute = new SourceFileAttribute { + Value = this.SourceFile } }); } - if (SourceDebugExtension != null) - { - if (Attributes.Any(x => x.Name == PredefinedAttributeNames.SourceDebugExtension)) - throw new Exception( - $"{PredefinedAttributeNames.SourceDebugExtension} attribute is already presented on field"); - Attributes.Add(new AttributeNode - { + if (this.SourceDebugExtension != null) { + if (this.Attributes.Any(x => x.Name == PredefinedAttributeNames.SourceDebugExtension)) + throw new Exception($"{PredefinedAttributeNames.SourceDebugExtension} attribute is already presented on field"); + this.Attributes.Add(new AttributeNode { Name = PredefinedAttributeNames.SourceDebugExtension, - ParsedAttribute = new SourceDebugExtensionAttribute - { - Value = SourceDebugExtension + ParsedAttribute = new SourceDebugExtensionAttribute { + Value = this.SourceDebugExtension } }); } - if (Signature != null) - { - if (Attributes.Any(x => x.Name == PredefinedAttributeNames.Signature)) - throw new Exception( - $"{PredefinedAttributeNames.Signature} attribute is already presented on field"); - Attributes.Add(new AttributeNode - { + if (this.Signature != null) { + if (this.Attributes.Any(x => x.Name == PredefinedAttributeNames.Signature)) + throw new Exception($"{PredefinedAttributeNames.Signature} attribute is already presented on field"); + this.Attributes.Add(new AttributeNode { Name = PredefinedAttributeNames.Signature, - ParsedAttribute = new SignatureAttribute - { - Value = Signature + ParsedAttribute = new SignatureAttribute { + Value = this.Signature } }); } - if (InvisibleAnnotations != null && InvisibleAnnotations.Count > 0) - { - if (Attributes.Any(x => x.Name == PredefinedAttributeNames.RuntimeInvisibleAnnotations)) - throw new Exception( - $"{PredefinedAttributeNames.RuntimeInvisibleAnnotations} attribute is already presented on field"); - Attributes.Add(new AttributeNode - { + if (this.InvisibleAnnotations != null && this.InvisibleAnnotations.Count > 0) { + if (this.Attributes.Any(x => x.Name == PredefinedAttributeNames.RuntimeInvisibleAnnotations)) + throw new Exception($"{PredefinedAttributeNames.RuntimeInvisibleAnnotations} attribute is already presented on field"); + this.Attributes.Add(new AttributeNode { Name = PredefinedAttributeNames.RuntimeInvisibleAnnotations, - ParsedAttribute = new RuntimeInvisibleAnnotationsAttribute - { - Annotations = InvisibleAnnotations + ParsedAttribute = new RuntimeInvisibleAnnotationsAttribute { + Annotations = this.InvisibleAnnotations } }); } - if (VisibleAnnotations != null && VisibleAnnotations.Count > 0) - { - if (Attributes.Any(x => x.Name == PredefinedAttributeNames.RuntimeVisibleAnnotations)) - throw new Exception( - $"{PredefinedAttributeNames.RuntimeVisibleAnnotations} attribute is already presented on field"); - Attributes.Add(new AttributeNode - { + if (this.VisibleAnnotations != null && this.VisibleAnnotations.Count > 0) { + if (this.Attributes.Any(x => x.Name == PredefinedAttributeNames.RuntimeVisibleAnnotations)) + throw new Exception($"{PredefinedAttributeNames.RuntimeVisibleAnnotations} attribute is already presented on field"); + this.Attributes.Add(new AttributeNode { Name = PredefinedAttributeNames.RuntimeVisibleAnnotations, - ParsedAttribute = new RuntimeVisibleAnnotationsAttribute - { - Annotations = VisibleAnnotations + ParsedAttribute = new RuntimeVisibleAnnotationsAttribute { + Annotations = this.VisibleAnnotations } }); } - if (IsDeprecated) - { - if (Attributes.Any(x => x.Name == PredefinedAttributeNames.Deprecated)) - throw new Exception( - $"{PredefinedAttributeNames.Deprecated} attribute is already presented on field"); - Attributes.Add(new AttributeNode - { + if (this.IsDeprecated) { + if (this.Attributes.Any(x => x.Name == PredefinedAttributeNames.Deprecated)) + throw new Exception($"{PredefinedAttributeNames.Deprecated} attribute is already presented on field"); + this.Attributes.Add(new AttributeNode { Name = PredefinedAttributeNames.Deprecated, ParsedAttribute = new DeprecatedAttribute() }); } - if (EnclosingMethod != null) - { - if (Attributes.Any(x => x.Name == PredefinedAttributeNames.EnclosingMethod)) - throw new Exception( - $"{PredefinedAttributeNames.EnclosingMethod} attribute is already presented on field"); - Attributes.Add(new AttributeNode - { + if (this.EnclosingMethod != null) { + if (this.Attributes.Any(x => x.Name == PredefinedAttributeNames.EnclosingMethod)) + throw new Exception($"{PredefinedAttributeNames.EnclosingMethod} attribute is already presented on field"); + this.Attributes.Add(new AttributeNode { Name = PredefinedAttributeNames.EnclosingMethod, - ParsedAttribute = EnclosingMethod + ParsedAttribute = this.EnclosingMethod }); } - if (InnerClasses != null) - { - if (Attributes.Any(x => x.Name == PredefinedAttributeNames.InnerClasses)) - throw new Exception( - $"{PredefinedAttributeNames.InnerClasses} attribute is already presented on field"); - Attributes.Add(new AttributeNode - { + if (this.InnerClasses != null && this.InnerClasses.Count > 0) { + if (this.Attributes.Any(x => x.Name == PredefinedAttributeNames.InnerClasses)) + throw new Exception($"{PredefinedAttributeNames.InnerClasses} attribute is already presented on field"); + this.Attributes.Add(new AttributeNode { Name = PredefinedAttributeNames.InnerClasses, - ParsedAttribute = new InnerClassesAttribute - { - Classes = InnerClasses + ParsedAttribute = new InnerClassesAttribute { + Classes = this.InnerClasses } }); } - foreach (var method in Methods) + foreach (MethodNode method in this.Methods) method.Save(writerState); - foreach (var field in Fields) + foreach (FieldNode field in this.Fields) field.Save(writerState); } - public override string ToString() - { - return $"{AccessModifiersExtensions.ToString(Access)} {Name}"; + public override string ToString() { + return $"{AccessModifiersExtensions.ToString(this.Access)} {this.Name}"; } } } \ No newline at end of file diff --git a/JavaAsm/ClassVersion.cs b/JavaAsm/ClassVersion.cs index 9f1d2d7..78d58dc 100644 --- a/JavaAsm/ClassVersion.cs +++ b/JavaAsm/ClassVersion.cs @@ -1,10 +1,8 @@ -namespace JavaAsm -{ +namespace JavaAsm { /// /// Class file version enum /// - public enum ClassVersion : ushort - { + public enum ClassVersion : ushort { Java1P1 = 45, Java1P2, Java1P3, diff --git a/JavaAsm/Commons/MethodHelper.cs b/JavaAsm/Commons/MethodHelper.cs index c5c4c96..7a96cab 100644 --- a/JavaAsm/Commons/MethodHelper.cs +++ b/JavaAsm/Commons/MethodHelper.cs @@ -5,52 +5,47 @@ using JavaAsm.Instructions; using JavaAsm.Instructions.Types; -namespace JavaAsm.Commons -{ +namespace JavaAsm.Commons { /// /// Helper class for different operations with methods (computing sizes, frames, etc) /// - public static class MethodHelper - { + public static class MethodHelper { /// /// Computers max number of locals and stack /// /// Method to compute for /// ValueTuple of max number of locals and stack - public static (ushort MaxLocals, ushort MaxStack) ComputeMaxStackAndLocals(MethodNode methodNode) - { + public static (ushort MaxLocals, ushort MaxStack) ComputeMaxStackAndLocals(MethodNode methodNode) { if (methodNode.Instructions == null || methodNode.Access.HasFlag(MethodAccessModifiers.Native) || methodNode.Access.HasFlag(MethodAccessModifiers.Abstract)) throw new ArgumentOutOfRangeException(nameof(methodNode), "Can't compute stack and locals for native or abstract method"); - var maxLocalIndex = Math.Max(methodNode.Instructions.Any(x => x is VariableInstruction) ? - methodNode.Instructions.Where(x => x is VariableInstruction).Max(x => ((VariableInstruction) x).VariableIndex + - (x.Opcode.In(Opcode.LLOAD, Opcode.LSTORE, Opcode.DLOAD, Opcode.DSTORE) ? 1 : 0)) + 1 : 0, - methodNode.Descriptor.ArgumentTypes.Sum(x => x.SizeOnStack) + (methodNode.Access.HasFlag(MethodAccessModifiers.Static) ? 0 : 1)); + int maxLocalIndex = Math.Max(methodNode.Instructions.Any(x => x is VariableInstruction) + ? methodNode.Instructions.Where(x => x is VariableInstruction).Max(x => ((VariableInstruction) x).VariableIndex + + (x.Opcode.In(Opcode.LLOAD, Opcode.LSTORE, Opcode.DLOAD, Opcode.DSTORE) ? 1 : 0)) + 1 + : 0, + methodNode.Descriptor.ArgumentTypes.Sum(x => x.SizeOnStack) + (methodNode.Access.HasFlag(MethodAccessModifiers.Static) ? 0 : 1)); if (maxLocalIndex > ushort.MaxValue) throw new ArgumentOutOfRangeException(nameof(maxLocalIndex), $"Max local index is larger that maximum possible amount: {maxLocalIndex} > {ushort.MaxValue}"); - var maxLocals = (ushort) maxLocalIndex; + ushort maxLocals = (ushort) maxLocalIndex; - var queueToCompute = new Queue(); + Queue queueToCompute = new Queue(); queueToCompute.Enqueue(methodNode.Instructions.First); - var stackSizes = new Dictionary - { - { methodNode.Instructions.First, 0 } + Dictionary stackSizes = new Dictionary { + {methodNode.Instructions.First, 0} }; - foreach (var tryCatchBlock in methodNode.TryCatches) - { + foreach (TryCatchNode tryCatchBlock in methodNode.TryCatches) { if (tryCatchBlock.Handler.OwnerList != methodNode.Instructions) throw new Exception("TryCatch block handler label does not belongs to methodNode's instructions list"); - if (stackSizes.TryAdd(tryCatchBlock.Handler, 1)) + if (stackSizes.TryAdd(tryCatchBlock.Handler, 1)) queueToCompute.Enqueue(tryCatchBlock.Handler); } - static void CheckStackSizeAndThrow(int stackSize) - { + void CheckStackSizeAndThrow(int stackSize) { if (stackSize < 0) throw new ArgumentOutOfRangeException(nameof(stackSize), $"Stack underflow: {stackSize} < {ushort.MinValue}"); @@ -59,8 +54,7 @@ static void CheckStackSizeAndThrow(int stackSize) $"Stack overflow: {stackSize} > {ushort.MaxValue}"); } - void EnqueueInstruction(Instruction instruction, int newStackSize) - { + void EnqueueInstruction(Instruction instruction, int newStackSize) { CheckStackSizeAndThrow(newStackSize); if (stackSizes.TryAdd(instruction, (ushort) newStackSize)) queueToCompute.Enqueue(instruction); @@ -68,15 +62,12 @@ void EnqueueInstruction(Instruction instruction, int newStackSize) throw new Exception($"Stack size difference on instruction {instruction}"); } - while (queueToCompute.Any()) - { - var currentInstruction = queueToCompute.Dequeue(); - var newStackSize = (int) stackSizes[currentInstruction]; - switch (currentInstruction) - { + while (queueToCompute.Any()) { + Instruction currentInstruction = queueToCompute.Dequeue(); + int newStackSize = stackSizes[currentInstruction]; + switch (currentInstruction) { case FieldInstruction fieldInstruction: - if (fieldInstruction.Opcode.In(Opcode.GETFIELD, Opcode.PUTFIELD)) - { + if (fieldInstruction.Opcode.In(Opcode.GETFIELD, Opcode.PUTFIELD)) { newStackSize--; CheckStackSizeAndThrow(newStackSize); } @@ -96,8 +87,7 @@ void EnqueueInstruction(Instruction instruction, int newStackSize) break; case JumpInstruction jumpInstruction: // ReSharper disable once SwitchStatementMissingSomeCases - switch (jumpInstruction.Opcode) - { + switch (jumpInstruction.Opcode) { case Opcode.IFEQ: case Opcode.IFNE: case Opcode.IFLT: @@ -127,9 +117,9 @@ void EnqueueInstruction(Instruction instruction, int newStackSize) case Opcode.GOTO: EnqueueInstruction(jumpInstruction.Target, newStackSize); continue; - default: - throw new ArgumentOutOfRangeException(nameof(jumpInstruction.Opcode)); + default: throw new ArgumentOutOfRangeException(nameof(jumpInstruction.Opcode)); } + break; case LdcInstruction ldcInstruction: newStackSize += ldcInstruction.Value is long || ldcInstruction.Value is double ? 2 : 1; @@ -137,12 +127,11 @@ void EnqueueInstruction(Instruction instruction, int newStackSize) case LookupSwitchInstruction lookupSwitchInstruction: newStackSize--; EnqueueInstruction(lookupSwitchInstruction.Default, newStackSize); - foreach (var jumpPoint in lookupSwitchInstruction.MatchLabels) + foreach (KeyValuePair jumpPoint in lookupSwitchInstruction.MatchLabels) EnqueueInstruction(jumpPoint.Value, newStackSize); continue; case MethodInstruction methodInstruction: - if (methodInstruction.Opcode != Opcode.INVOKESTATIC) - { + if (methodInstruction.Opcode != Opcode.INVOKESTATIC) { newStackSize--; CheckStackSizeAndThrow(newStackSize); } @@ -163,10 +152,8 @@ void EnqueueInstruction(Instruction instruction, int newStackSize) break; case SimpleInstruction simpleInstruction: // ReSharper disable once SwitchStatementMissingSomeCases - switch (simpleInstruction.Opcode) - { - case Opcode.NOP: - break; + switch (simpleInstruction.Opcode) { + case Opcode.NOP: break; case Opcode.ACONST_NULL: case Opcode.ICONST_M1: case Opcode.ICONST_0: @@ -178,24 +165,24 @@ void EnqueueInstruction(Instruction instruction, int newStackSize) case Opcode.FCONST_0: case Opcode.FCONST_1: case Opcode.FCONST_2: - newStackSize++; - break; + newStackSize++; + break; case Opcode.LCONST_0: case Opcode.LCONST_1: case Opcode.DCONST_0: case Opcode.DCONST_1: - newStackSize += 2; - break; + newStackSize += 2; + break; case Opcode.IALOAD: case Opcode.FALOAD: case Opcode.AALOAD: case Opcode.BALOAD: case Opcode.CALOAD: case Opcode.SALOAD: - newStackSize -= 2; - CheckStackSizeAndThrow(newStackSize); - newStackSize++; - break; + newStackSize -= 2; + CheckStackSizeAndThrow(newStackSize); + newStackSize++; + break; case Opcode.LALOAD: case Opcode.DALOAD: newStackSize -= 2; @@ -207,10 +194,10 @@ void EnqueueInstruction(Instruction instruction, int newStackSize) case Opcode.I2D: case Opcode.F2L: case Opcode.F2D: - newStackSize--; - CheckStackSizeAndThrow(newStackSize); - newStackSize += 2; - break; + newStackSize--; + CheckStackSizeAndThrow(newStackSize); + newStackSize += 2; + break; case Opcode.IASTORE: case Opcode.FASTORE: case Opcode.AASTORE: @@ -220,51 +207,51 @@ void EnqueueInstruction(Instruction instruction, int newStackSize) newStackSize -= 3; break; case Opcode.POP2: - newStackSize -= 2; - break; + newStackSize -= 2; + break; case Opcode.DASTORE: case Opcode.LASTORE: - newStackSize -= 4; - break; + newStackSize -= 4; + break; case Opcode.POP: case Opcode.MONITORENTER: case Opcode.MONITOREXIT: - newStackSize--; - break; + newStackSize--; + break; case Opcode.DUP_X1: - newStackSize -= 2; + newStackSize -= 2; CheckStackSizeAndThrow(newStackSize); - newStackSize += 3; - break; + newStackSize += 3; + break; case Opcode.DUP_X2: - newStackSize -= 3; + newStackSize -= 3; CheckStackSizeAndThrow(newStackSize); - newStackSize += 4; - break; + newStackSize += 4; + break; case Opcode.DUP2: - newStackSize -= 2; + newStackSize -= 2; CheckStackSizeAndThrow(newStackSize); - newStackSize += 4; - break; + newStackSize += 4; + break; case Opcode.DUP2_X1: - newStackSize -= 3; + newStackSize -= 3; CheckStackSizeAndThrow(newStackSize); - newStackSize += 5; - break; + newStackSize += 5; + break; case Opcode.DUP2_X2: - newStackSize -= 4; + newStackSize -= 4; CheckStackSizeAndThrow(newStackSize); - newStackSize += 6; - break; + newStackSize += 6; + break; case Opcode.SWAP: case Opcode.LNEG: case Opcode.DNEG: case Opcode.L2D: case Opcode.D2L: - newStackSize -= 2; - CheckStackSizeAndThrow(newStackSize); - newStackSize += 2; - break; + newStackSize -= 2; + CheckStackSizeAndThrow(newStackSize); + newStackSize += 2; + break; case Opcode.IADD: case Opcode.FADD: case Opcode.ISUB: @@ -283,10 +270,10 @@ void EnqueueInstruction(Instruction instruction, int newStackSize) case Opcode.IUSHR: case Opcode.FCMPL: case Opcode.FCMPG: - newStackSize -= 2; - CheckStackSizeAndThrow(newStackSize); - newStackSize++; - break; + newStackSize -= 2; + CheckStackSizeAndThrow(newStackSize); + newStackSize++; + break; case Opcode.LADD: case Opcode.DADD: case Opcode.LSUB: @@ -300,10 +287,10 @@ void EnqueueInstruction(Instruction instruction, int newStackSize) case Opcode.LAND: case Opcode.LOR: case Opcode.LXOR: - newStackSize -= 4; - CheckStackSizeAndThrow(newStackSize); - newStackSize += 2; - break; + newStackSize -= 4; + CheckStackSizeAndThrow(newStackSize); + newStackSize += 2; + break; case Opcode.INEG: case Opcode.FNEG: case Opcode.I2F: @@ -312,61 +299,59 @@ void EnqueueInstruction(Instruction instruction, int newStackSize) case Opcode.I2C: case Opcode.I2S: case Opcode.ARRAYLENGTH: - newStackSize--; - CheckStackSizeAndThrow(newStackSize); - newStackSize++; - break; + newStackSize--; + CheckStackSizeAndThrow(newStackSize); + newStackSize++; + break; case Opcode.LSHL: case Opcode.LSHR: case Opcode.LUSHR: - newStackSize -= 3; - CheckStackSizeAndThrow(newStackSize); - newStackSize += 2; - break; + newStackSize -= 3; + CheckStackSizeAndThrow(newStackSize); + newStackSize += 2; + break; case Opcode.L2I: case Opcode.L2F: case Opcode.D2I: case Opcode.D2F: - newStackSize -= 2; - CheckStackSizeAndThrow(newStackSize); - newStackSize++; - break; + newStackSize -= 2; + CheckStackSizeAndThrow(newStackSize); + newStackSize++; + break; case Opcode.LCMP: case Opcode.DCMPL: case Opcode.DCMPG: - newStackSize -= 4; - CheckStackSizeAndThrow(newStackSize); - newStackSize++; - break; + newStackSize -= 4; + CheckStackSizeAndThrow(newStackSize); + newStackSize++; + break; case Opcode.ARETURN: case Opcode.IRETURN: case Opcode.FRETURN: case Opcode.ATHROW: - newStackSize--; - CheckStackSizeAndThrow(newStackSize); - continue; + newStackSize--; + CheckStackSizeAndThrow(newStackSize); + continue; case Opcode.LRETURN: case Opcode.DRETURN: - newStackSize -= 2; - CheckStackSizeAndThrow(newStackSize); - continue; - case Opcode.RETURN: - continue; - default: - throw new ArgumentOutOfRangeException(nameof(simpleInstruction.Opcode)); + newStackSize -= 2; + CheckStackSizeAndThrow(newStackSize); + continue; + case Opcode.RETURN: continue; + default: throw new ArgumentOutOfRangeException(nameof(simpleInstruction.Opcode)); } + break; case TableSwitchInstruction tableSwitchInstruction: newStackSize--; CheckStackSizeAndThrow(newStackSize); EnqueueInstruction(tableSwitchInstruction.Default, newStackSize); - foreach (var jumpPoint in tableSwitchInstruction.Labels) + foreach (Label jumpPoint in tableSwitchInstruction.Labels) EnqueueInstruction(jumpPoint, newStackSize); continue; case TypeInstruction typeInstruction: // ReSharper disable once SwitchStatementMissingSomeCases - switch (typeInstruction.Opcode) - { + switch (typeInstruction.Opcode) { case Opcode.NEW: newStackSize++; break; @@ -377,14 +362,13 @@ void EnqueueInstruction(Instruction instruction, int newStackSize) CheckStackSizeAndThrow(newStackSize); newStackSize++; break; - default: - throw new ArgumentOutOfRangeException(nameof(typeInstruction.Opcode)); + default: throw new ArgumentOutOfRangeException(nameof(typeInstruction.Opcode)); } + break; case VariableInstruction variableInstruction: // ReSharper disable once SwitchStatementMissingSomeCases - switch (variableInstruction.Opcode) - { + switch (variableInstruction.Opcode) { case Opcode.ALOAD: case Opcode.ILOAD: case Opcode.FLOAD: @@ -403,21 +387,19 @@ void EnqueueInstruction(Instruction instruction, int newStackSize) case Opcode.DSTORE: newStackSize -= 2; break; - case Opcode.RET: - break; - default: - throw new ArgumentOutOfRangeException(nameof(variableInstruction.Opcode)); + case Opcode.RET: break; + default: throw new ArgumentOutOfRangeException(nameof(variableInstruction.Opcode)); } + break; case StackMapFrame _: case IncrementInstruction _: case LineNumber _: case Label _: break; - default: - throw new ArgumentOutOfRangeException(nameof(currentInstruction)); + default: throw new ArgumentOutOfRangeException(nameof(currentInstruction)); } - + EnqueueInstruction(currentInstruction.Next, newStackSize); } @@ -428,9 +410,8 @@ void EnqueueInstruction(Instruction instruction, int newStackSize) /// Computes stack frames /// /// Method to compute for - public static void ComputeStackMapFrames(MethodNode methodNode) - { + public static void ComputeStackMapFrames(MethodNode methodNode) { throw new NotImplementedException(); } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/Annotation/AnnotationNode.cs b/JavaAsm/CustomAttributes/Annotation/AnnotationNode.cs index 108f7f8..77adfec 100644 --- a/JavaAsm/CustomAttributes/Annotation/AnnotationNode.cs +++ b/JavaAsm/CustomAttributes/Annotation/AnnotationNode.cs @@ -5,14 +5,11 @@ using JavaAsm.IO; using JavaAsm.IO.ConstantPoolEntries; -namespace JavaAsm.CustomAttributes.Annotation -{ - public class AnnotationNode - { +namespace JavaAsm.CustomAttributes.Annotation { + public class AnnotationNode { public TypeDescriptor Type { get; set; } - public class ElementValuePair - { + public class ElementValuePair { public string ElementName { get; set; } public ElementValue Value { get; set; } @@ -20,38 +17,31 @@ public class ElementValuePair public List ElementValuePairs { get; set; } = new List(); - internal static AnnotationNode Parse(Stream stream, ClassReaderState readerState) - { - var annotation = new AnnotationNode - { - Type = TypeDescriptor.Parse(readerState.ConstantPool - .GetEntry(Binary.BigEndian.ReadUInt16(stream)).String) + internal static AnnotationNode Parse(Stream stream, ClassReaderState readerState) { + AnnotationNode annotation = new AnnotationNode { + Type = TypeDescriptor.Parse(readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(stream)).String) }; - var elementValuePairsCount = Binary.BigEndian.ReadUInt16(stream); + ushort elementValuePairsCount = Binary.BigEndian.ReadUInt16(stream); annotation.ElementValuePairs.Capacity = elementValuePairsCount; - for (var i = 0; i < elementValuePairsCount; i++) - annotation.ElementValuePairs.Add(new ElementValuePair - { - ElementName = readerState.ConstantPool - .GetEntry(Binary.BigEndian.ReadUInt16(stream)).String, + for (int i = 0; i < elementValuePairsCount; i++) + annotation.ElementValuePairs.Add(new ElementValuePair { + ElementName = readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(stream)).String, Value = ElementValue.Parse(stream, readerState) }); return annotation; } - internal void Write(Stream stream, ClassWriterState writerState) - { - Binary.BigEndian.Write(stream, writerState.ConstantPool.Find(new Utf8Entry(Type.ToString()))); - if (ElementValuePairs.Count > ushort.MaxValue) - throw new ArgumentOutOfRangeException(nameof(ElementValuePairs.Count), - $"Too many ElementValues: {ElementValuePairs.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(stream, (ushort) ElementValuePairs.Count); - foreach (var elementValuePair in ElementValuePairs) - { + internal void Write(Stream stream, ClassWriterState writerState) { + Binary.BigEndian.Write(stream, writerState.ConstantPool.Find(new Utf8Entry(this.Type.ToString()))); + if (this.ElementValuePairs.Count > ushort.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.ElementValuePairs.Count), + $"Too many ElementValues: {this.ElementValuePairs.Count} > {ushort.MaxValue}"); + Binary.BigEndian.Write(stream, (ushort) this.ElementValuePairs.Count); + foreach (ElementValuePair elementValuePair in this.ElementValuePairs) { Binary.BigEndian.Write(stream, writerState.ConstantPool.Find(new Utf8Entry(elementValuePair.ElementName))); elementValuePair.Value.Write(stream, writerState); } } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/Annotation/ElementValue.cs b/JavaAsm/CustomAttributes/Annotation/ElementValue.cs index 61e2a8f..55c6a2f 100644 --- a/JavaAsm/CustomAttributes/Annotation/ElementValue.cs +++ b/JavaAsm/CustomAttributes/Annotation/ElementValue.cs @@ -6,12 +6,9 @@ using JavaAsm.IO; using JavaAsm.IO.ConstantPoolEntries; -namespace JavaAsm.CustomAttributes.Annotation -{ - public class ElementValue - { - public enum ElementValueTag - { +namespace JavaAsm.CustomAttributes.Annotation { + public class ElementValue { + public enum ElementValueTag { Byte = 'B', Character = 'C', Double = 'D', @@ -29,10 +26,16 @@ public enum ElementValueTag public ElementValueTag Tag { get; set; } - public object ConstValue { get; set; } + private object constValue; - public class EnumConstValueType - { + public object ConstValue { + get => this.constValue; + set { + this.constValue = value; + } + } + + public class EnumConstValueType { public TypeDescriptor TypeName { get; set; } public string ConstName { get; set; } @@ -46,15 +49,12 @@ public class EnumConstValueType public List ArrayValue { get; set; } - internal static ElementValue Parse(Stream stream, ClassReaderState readerState) - { - var elementValue = new ElementValue - { + internal static ElementValue Parse(Stream stream, ClassReaderState readerState) { + ElementValue elementValue = new ElementValue { Tag = (ElementValueTag) stream.ReadByteFully() }; - switch (elementValue.Tag) - { + switch (elementValue.Tag) { case ElementValueTag.Byte: case ElementValueTag.Character: case ElementValueTag.Integer: @@ -75,81 +75,73 @@ internal static ElementValue Parse(Stream stream, ClassReaderState readerState) elementValue.ConstValue = readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(stream)).String; break; case ElementValueTag.Enum: - elementValue.EnumConstValue = new EnumConstValueType - { - TypeName = TypeDescriptor.Parse(readerState.ConstantPool - .GetEntry(Binary.BigEndian.ReadUInt16(stream)).String), - ConstName = readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(stream)) - .String + elementValue.EnumConstValue = new EnumConstValueType { + TypeName = TypeDescriptor.Parse(readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(stream)).String), + ConstName = readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(stream)).String }; break; case ElementValueTag.Class: - elementValue.Class = TypeDescriptor.Parse(readerState.ConstantPool - .GetEntry(Binary.BigEndian.ReadUInt16(stream)).String, true); + elementValue.Class = TypeDescriptor.Parse(readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(stream)).String, true); break; case ElementValueTag.Annotation: elementValue.AnnotationNode = AnnotationNode.Parse(stream, readerState); break; case ElementValueTag.Array: - var arraySize = Binary.BigEndian.ReadUInt16(stream); + ushort arraySize = Binary.BigEndian.ReadUInt16(stream); elementValue.ArrayValue = new List(arraySize); - for (var i = 0; i < arraySize; i++) + for (int i = 0; i < arraySize; i++) elementValue.ArrayValue.Add(Parse(stream, readerState)); break; - default: - throw new ArgumentOutOfRangeException(nameof(elementValue.Tag)); + default: throw new ArgumentOutOfRangeException(nameof(elementValue.Tag)); } return elementValue; } - internal void Write(Stream stream, ClassWriterState writerState) - { - stream.WriteByte((byte) Tag); - switch (Tag) - { + internal void Write(Stream stream, ClassWriterState writerState) { + stream.WriteByte((byte) this.Tag); + switch (this.Tag) { case ElementValueTag.Byte: case ElementValueTag.Character: case ElementValueTag.Integer: case ElementValueTag.Short: case ElementValueTag.Boolean: - Binary.BigEndian.Write(stream, writerState.ConstantPool.Find(new IntegerEntry((int) ConstValue))); + Binary.BigEndian.Write(stream, writerState.ConstantPool.Find(new IntegerEntry((int) this.ConstValue))); break; case ElementValueTag.Double: - Binary.BigEndian.Write(stream, writerState.ConstantPool.Find(new DoubleEntry((double) ConstValue))); + Binary.BigEndian.Write(stream, writerState.ConstantPool.Find(new DoubleEntry((double) this.ConstValue))); break; case ElementValueTag.Float: - Binary.BigEndian.Write(stream, writerState.ConstantPool.Find(new FloatEntry((float) ConstValue))); + Binary.BigEndian.Write(stream, writerState.ConstantPool.Find(new FloatEntry((float) this.ConstValue))); break; case ElementValueTag.Long: - Binary.BigEndian.Write(stream, writerState.ConstantPool.Find(new LongEntry((long) ConstValue))); + Binary.BigEndian.Write(stream, writerState.ConstantPool.Find(new LongEntry((long) this.ConstValue))); break; case ElementValueTag.String: - Binary.BigEndian.Write(stream, writerState.ConstantPool.Find(new Utf8Entry((string) ConstValue))); + Binary.BigEndian.Write(stream, writerState.ConstantPool.Find(new Utf8Entry((string) this.ConstValue))); break; case ElementValueTag.Enum: Binary.BigEndian.Write(stream, - writerState.ConstantPool.Find(new Utf8Entry(EnumConstValue.TypeName.ToString()))); + writerState.ConstantPool.Find(new Utf8Entry(this.EnumConstValue.TypeName.ToString()))); Binary.BigEndian.Write(stream, - writerState.ConstantPool.Find(new Utf8Entry(EnumConstValue.ConstName))); + writerState.ConstantPool.Find(new Utf8Entry(this.EnumConstValue.ConstName))); break; case ElementValueTag.Class: Binary.BigEndian.Write(stream, - writerState.ConstantPool.Find(new Utf8Entry(Class.ToString()))); + writerState.ConstantPool.Find(new Utf8Entry(this.Class.ToString()))); break; case ElementValueTag.Annotation: - AnnotationNode.Write(stream, writerState); + this.AnnotationNode.Write(stream, writerState); break; case ElementValueTag.Array: - if (ArrayValue.Count > ushort.MaxValue) - throw new ArgumentOutOfRangeException(nameof(ArrayValue.Count), $"Array size is too big: {ArrayValue.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(stream, (ushort) ArrayValue.Count); - foreach (var element in ArrayValue) + if (this.ArrayValue.Count > ushort.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.ArrayValue.Count), $"Array size is too big: {this.ArrayValue.Count} > {ushort.MaxValue}"); + Binary.BigEndian.Write(stream, (ushort) this.ArrayValue.Count); + foreach (ElementValue element in this.ArrayValue) element.Write(stream, writerState); break; - default: - throw new ArgumentOutOfRangeException(nameof(Tag)); + default: throw new ArgumentOutOfRangeException(nameof(this.Tag)); } } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/AnnotationDefaultAttribute.cs b/JavaAsm/CustomAttributes/AnnotationDefaultAttribute.cs index 3472c27..6d4f25c 100644 --- a/JavaAsm/CustomAttributes/AnnotationDefaultAttribute.cs +++ b/JavaAsm/CustomAttributes/AnnotationDefaultAttribute.cs @@ -2,30 +2,24 @@ using JavaAsm.CustomAttributes.Annotation; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes -{ - public class AnnotationDefaultAttribute : CustomAttribute - { +namespace JavaAsm.CustomAttributes { + public class AnnotationDefaultAttribute : CustomAttribute { public ElementValue Value { get; set; } - internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) - { - using var attributeDataStream = new MemoryStream(); + internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) { + MemoryStream attributeDataStream = new MemoryStream(); - Value.Write(attributeDataStream, writerState); + this.Value.Write(attributeDataStream, writerState); return attributeDataStream.ToArray(); } } - internal class AnnotationDefaultAttributeFactory : ICustomAttributeFactory - { - public AnnotationDefaultAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) - { - return new AnnotationDefaultAttribute - { + internal class AnnotationDefaultAttributeFactory : ICustomAttributeFactory { + public AnnotationDefaultAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) { + return new AnnotationDefaultAttribute { Value = ElementValue.Parse(attributeDataStream, readerState) }; } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/BootstrapMethodsAttribute.cs b/JavaAsm/CustomAttributes/BootstrapMethodsAttribute.cs index 60f8023..c8ead35 100644 --- a/JavaAsm/CustomAttributes/BootstrapMethodsAttribute.cs +++ b/JavaAsm/CustomAttributes/BootstrapMethodsAttribute.cs @@ -6,124 +6,144 @@ using JavaAsm.IO; using JavaAsm.IO.ConstantPoolEntries; -namespace JavaAsm.CustomAttributes -{ - public class BootstrapMethod - { +namespace JavaAsm.CustomAttributes { + public class BootstrapMethod { public Handle BootstrapMethodReference { get; } public List Arguments { get; } = new List(); - public BootstrapMethod(Handle bootstrapMethodReference) - { - BootstrapMethodReference = bootstrapMethodReference; + public BootstrapMethod(Handle bootstrapMethodReference) { + this.BootstrapMethodReference = bootstrapMethodReference; } - public BootstrapMethod(Handle bootstrapMethodReference, List arguments) - { - BootstrapMethodReference = bootstrapMethodReference; - Arguments = arguments; + public BootstrapMethod(Handle bootstrapMethodReference, List arguments) { + this.BootstrapMethodReference = bootstrapMethodReference; + this.Arguments = arguments; } - public bool Equals(BootstrapMethod other) - { - return BootstrapMethodReference.Equals(other.BootstrapMethodReference) && Arguments.Equals(other.Arguments); + public bool Equals(BootstrapMethod other) { + return this.BootstrapMethodReference.Equals(other.BootstrapMethodReference) && this.Arguments.Equals(other.Arguments); } - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == GetType() && Equals((BootstrapMethod)obj); + public override bool Equals(object obj) { + if (ReferenceEquals(null, obj)) + return false; + if (ReferenceEquals(this, obj)) + return true; + return obj.GetType() == GetType() && Equals((BootstrapMethod) obj); } - public override int GetHashCode() - { - unchecked - { - return (BootstrapMethodReference.GetHashCode() * 397) ^ Arguments.GetHashCode(); + public override int GetHashCode() { + unchecked { + return (this.BootstrapMethodReference.GetHashCode() * 397) ^ this.Arguments.GetHashCode(); } } } - internal class BootstrapMethodsAttribute : CustomAttribute - { + internal class BootstrapMethodsAttribute : CustomAttribute { public List BootstrapMethods { get; set; } = new List(); - internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) - { - using var attributeDataStream = new MemoryStream(); - - if (BootstrapMethods.Count > ushort.MaxValue) - throw new ArgumentOutOfRangeException(nameof(BootstrapMethods.Count), $"Number of bootstrap methods is too big: {BootstrapMethods.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(attributeDataStream, (ushort) BootstrapMethods.Count); - foreach (var method in BootstrapMethods) - { - Binary.BigEndian.Write(attributeDataStream, - writerState.ConstantPool.Find(method.BootstrapMethodReference.ToConstantPool())); - if (method.Arguments.Count > ushort.MaxValue) - throw new ArgumentOutOfRangeException(nameof(method.Arguments.Count), - $"Number of arguments is too big: {method.Arguments.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(attributeDataStream, (ushort) method.Arguments.Count); - foreach (var argument in method.Arguments) - { - Binary.BigEndian.Write(attributeDataStream, writerState.ConstantPool.Find(argument switch - { - int integerValue => (Entry) new IntegerEntry(integerValue), - float floatValue => new FloatEntry(floatValue), - string stringValue => new StringEntry(new Utf8Entry(stringValue)), - long longValue => new LongEntry(longValue), - double doubleValue => new DoubleEntry(doubleValue), - Handle handle => handle.ToConstantPool(), - MethodDescriptor methodDescriptor => new MethodTypeEntry(new Utf8Entry(methodDescriptor.ToString())), - _ => throw new ArgumentOutOfRangeException(nameof(argument), $"Can't encode value of type {argument.GetType()}") - })); + internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) { + using (MemoryStream attributeDataStream = new MemoryStream()) { + if (this.BootstrapMethods.Count > ushort.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.BootstrapMethods.Count), $"Number of bootstrap methods is too big: {this.BootstrapMethods.Count} > {ushort.MaxValue}"); + Binary.BigEndian.Write(attributeDataStream, (ushort) this.BootstrapMethods.Count); + foreach (BootstrapMethod method in this.BootstrapMethods) { + Binary.BigEndian.Write(attributeDataStream, + writerState.ConstantPool.Find(method.BootstrapMethodReference.ToConstantPool())); + if (method.Arguments.Count > ushort.MaxValue) + throw new ArgumentOutOfRangeException(nameof(method.Arguments.Count), + $"Number of arguments is too big: {method.Arguments.Count} > {ushort.MaxValue}"); + Binary.BigEndian.Write(attributeDataStream, (ushort) method.Arguments.Count); + foreach (object argument in method.Arguments) { + Entry val; + if (argument is int) { + val = new IntegerEntry((int) argument); + } + else if (argument is float) { + val = new FloatEntry((float) argument); + } + else if (argument is string) { + val = new StringEntry(new Utf8Entry((string) argument)); + } + else if (argument is long) { + val = new LongEntry((long) argument); + } + else if (argument is double) { + val = new DoubleEntry((double) argument); + } + else if (argument is Handle) { + val = ((Handle) argument).ToConstantPool(); + } + else if (argument is MethodDescriptor) { + val = new MethodTypeEntry(new Utf8Entry(((MethodDescriptor) argument).ToString())); + } + else { + throw new ArgumentOutOfRangeException(nameof(argument), $"Can't encode value of type {argument.GetType()}"); + } + + Binary.BigEndian.Write(attributeDataStream, writerState.ConstantPool.Find(val)); + } } - } - return attributeDataStream.ToArray(); + return attributeDataStream.ToArray(); + } } } - internal class BootstrapMethodsAttributeFactory : ICustomAttributeFactory - { - public BootstrapMethodsAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) - { - var attribute = new BootstrapMethodsAttribute(); + internal class BootstrapMethodsAttributeFactory : ICustomAttributeFactory { + public BootstrapMethodsAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) { + BootstrapMethodsAttribute attribute = new BootstrapMethodsAttribute(); - var bootstrapMethodsCount = Binary.BigEndian.ReadUInt16(attributeDataStream); + ushort bootstrapMethodsCount = Binary.BigEndian.ReadUInt16(attributeDataStream); attribute.BootstrapMethods.Capacity = bootstrapMethodsCount; - for (var i = 0; i < bootstrapMethodsCount; i++) - { - var bootstrapMethod = new BootstrapMethod( + for (int i = 0; i < bootstrapMethodsCount; i++) { + BootstrapMethod bootstrapMethod = new BootstrapMethod( Handle.FromConstantPool( readerState.ConstantPool.GetEntry( Binary.BigEndian.ReadUInt16(attributeDataStream)))); - var numberOfArguments = Binary.BigEndian.ReadUInt16(attributeDataStream); + ushort numberOfArguments = Binary.BigEndian.ReadUInt16(attributeDataStream); bootstrapMethod.Arguments.Capacity = numberOfArguments; - for (var j = 0; j < numberOfArguments; j++) - { - var argumentValueEntry = + for (int j = 0; j < numberOfArguments; j++) { + Entry argumentValueEntry = readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(attributeDataStream)); - bootstrapMethod.Arguments.Add(argumentValueEntry switch - { - StringEntry stringEntry => stringEntry.Value.String, - ClassEntry classEntry => new ClassName(classEntry.Name.String), - IntegerEntry integerEntry => (object) integerEntry.Value, - LongEntry longEntry => longEntry.Value, - FloatEntry floatEntry => floatEntry.Value, - DoubleEntry doubleEntry => doubleEntry.Value, - MethodHandleEntry methodHandleEntry => Handle.FromConstantPool(methodHandleEntry), - MethodTypeEntry methodTypeEntry => MethodDescriptor.Parse(methodTypeEntry.Descriptor.String), - _ => throw new ArgumentOutOfRangeException(nameof(argumentValueEntry), - $"Entry of type {argumentValueEntry.Tag} is not supported for argument of bootstrap method") - }); + object item; + if (argumentValueEntry is StringEntry se) { + item = se.Value.String; + } + else if (argumentValueEntry is ClassEntry ce) { + item = new ClassName(ce.Name.String); + } + else if (argumentValueEntry is IntegerEntry ie) { + item = ie.Value; + } + else if (argumentValueEntry is LongEntry le) { + item = le.Value; + } + else if (argumentValueEntry is FloatEntry fe) { + item = fe.Value; + } + else if (argumentValueEntry is DoubleEntry de) { + item = de.Value; + } + else if (argumentValueEntry is MethodHandleEntry mhe) { + item = Handle.FromConstantPool(mhe); + } + else if (argumentValueEntry is MethodTypeEntry mte) { + item = MethodDescriptor.Parse(mte.Descriptor.String); + } + else { + throw new ArgumentOutOfRangeException(nameof(argumentValueEntry), $"Entry of type {argumentValueEntry.Tag} is not supported for argument of bootstrap method"); + } + + bootstrapMethod.Arguments.Add(item); } + attribute.BootstrapMethods.Add(bootstrapMethod); } return attribute; } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/CodeAttribute.cs b/JavaAsm/CustomAttributes/CodeAttribute.cs index e1adc01..f079a13 100644 --- a/JavaAsm/CustomAttributes/CodeAttribute.cs +++ b/JavaAsm/CustomAttributes/CodeAttribute.cs @@ -2,21 +2,19 @@ using System.Collections.Generic; using System.IO; using BinaryEncoding; +using JavaAsm.Helpers; using JavaAsm.IO; using JavaAsm.IO.ConstantPoolEntries; -namespace JavaAsm.CustomAttributes -{ - public class CodeAttribute : CustomAttribute - { +namespace JavaAsm.CustomAttributes { + public class CodeAttribute : CustomAttribute { public ushort MaxStack { get; set; } public ushort MaxLocals { get; set; } public byte[] Code { get; set; } - public class ExceptionTableEntry - { + public class ExceptionTableEntry { public ushort StartPc { get; set; } public ushort EndPc { get; set; } @@ -30,83 +28,72 @@ public class ExceptionTableEntry public List Attributes { get; set; } = new List(); - internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) - { - using var attributeDataStream = new MemoryStream(); + internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) { + MemoryStream attributeDataStream = new MemoryStream(); - Binary.BigEndian.Write(attributeDataStream, MaxStack); - Binary.BigEndian.Write(attributeDataStream, MaxLocals); + Binary.BigEndian.Write(attributeDataStream, this.MaxStack); + Binary.BigEndian.Write(attributeDataStream, this.MaxLocals); - if (Code.LongLength > uint.MaxValue) - throw new ArgumentOutOfRangeException(nameof(Code.LongLength), $"Code length too big: {Code.LongLength} > {uint.MaxValue}"); - Binary.BigEndian.Write(attributeDataStream, (uint) Code.LongLength); - attributeDataStream.Write(Code); + if (this.Code.LongLength > uint.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.Code.LongLength), $"Code length too big: {this.Code.LongLength} > {uint.MaxValue}"); + Binary.BigEndian.Write(attributeDataStream, (uint) this.Code.LongLength); + attributeDataStream.Write(this.Code); - if (ExceptionTable.Count > ushort.MaxValue) - throw new ArgumentOutOfRangeException(nameof(ExceptionTable.Count), $"Exception table too big: {ExceptionTable.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(attributeDataStream, (ushort) ExceptionTable.Count); - foreach (var exceptionTableEntry in ExceptionTable) - { + if (this.ExceptionTable.Count > ushort.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.ExceptionTable.Count), $"Exception table too big: {this.ExceptionTable.Count} > {ushort.MaxValue}"); + Binary.BigEndian.Write(attributeDataStream, (ushort) this.ExceptionTable.Count); + foreach (ExceptionTableEntry exceptionTableEntry in this.ExceptionTable) { Binary.BigEndian.Write(attributeDataStream, exceptionTableEntry.StartPc); Binary.BigEndian.Write(attributeDataStream, exceptionTableEntry.EndPc); Binary.BigEndian.Write(attributeDataStream, exceptionTableEntry.HandlerPc); - Binary.BigEndian.Write(attributeDataStream, (ushort) (exceptionTableEntry.CatchType == null ? 0 : - writerState.ConstantPool.Find(new ClassEntry(new Utf8Entry(exceptionTableEntry.CatchType.Name))))); + Binary.BigEndian.Write(attributeDataStream, (ushort) (exceptionTableEntry.CatchType == null ? 0 : writerState.ConstantPool.Find(new ClassEntry(new Utf8Entry(exceptionTableEntry.CatchType.Name))))); } - if (Attributes.Count > ushort.MaxValue) - throw new ArgumentOutOfRangeException(nameof(Attributes.Count), $"Too many attributes: {Attributes.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(attributeDataStream, (ushort) Attributes.Count); - foreach (var attriute in Attributes) + if (this.Attributes.Count > ushort.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.Attributes.Count), $"Too many attributes: {this.Attributes.Count} > {ushort.MaxValue}"); + Binary.BigEndian.Write(attributeDataStream, (ushort) this.Attributes.Count); + foreach (AttributeNode attriute in this.Attributes) ClassFile.WriteAttribute(attributeDataStream, attriute, writerState, AttributeScope.Code); return attributeDataStream.ToArray(); } } - internal class CodeAttributeFactory : ICustomAttributeFactory - { - public CodeAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) - { - var maxStack = Binary.BigEndian.ReadUInt16(attributeDataStream); - var maxLocals = Binary.BigEndian.ReadUInt16(attributeDataStream); - var code = new byte[Binary.BigEndian.ReadUInt32(attributeDataStream)]; + internal class CodeAttributeFactory : ICustomAttributeFactory { + public CodeAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) { + ushort maxStack = Binary.BigEndian.ReadUInt16(attributeDataStream); + ushort maxLocals = Binary.BigEndian.ReadUInt16(attributeDataStream); + byte[] code = new byte[Binary.BigEndian.ReadUInt32(attributeDataStream)]; attributeDataStream.Read(code); - var attribute = new CodeAttribute - { + CodeAttribute attribute = new CodeAttribute { MaxStack = maxStack, MaxLocals = maxLocals, Code = code }; - var exceptionTableSize = Binary.BigEndian.ReadUInt16(attributeDataStream); + ushort exceptionTableSize = Binary.BigEndian.ReadUInt16(attributeDataStream); attribute.ExceptionTable.Capacity = exceptionTableSize; - for (var i = 0; i < exceptionTableSize; i++) - { - var exceptionTableEntry = new CodeAttribute.ExceptionTableEntry - { + for (int i = 0; i < exceptionTableSize; i++) { + CodeAttribute.ExceptionTableEntry exceptionTableEntry = new CodeAttribute.ExceptionTableEntry { StartPc = Binary.BigEndian.ReadUInt16(attributeDataStream), EndPc = Binary.BigEndian.ReadUInt16(attributeDataStream), HandlerPc = Binary.BigEndian.ReadUInt16(attributeDataStream) }; - var catchTypeIndex = Binary.BigEndian.ReadUInt16(attributeDataStream); + ushort catchTypeIndex = Binary.BigEndian.ReadUInt16(attributeDataStream); - if (catchTypeIndex != 0) - { - exceptionTableEntry.CatchType = new ClassName(readerState.ConstantPool - .GetEntry(catchTypeIndex) - .Name.String); + if (catchTypeIndex != 0) { + exceptionTableEntry.CatchType = new ClassName(readerState.ConstantPool.GetEntry(catchTypeIndex).Name.String); } attribute.ExceptionTable.Add(exceptionTableEntry); } - var attributesCount = Binary.BigEndian.ReadUInt16(attributeDataStream); + ushort attributesCount = Binary.BigEndian.ReadUInt16(attributeDataStream); attribute.Attributes.Capacity = attributesCount; - for (var i = 0; i < attributesCount; i++) + for (int i = 0; i < attributesCount; i++) attribute.Attributes.Add(ClassFile.ParseAttribute(attributeDataStream, readerState, AttributeScope.Code)); return attribute; } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/ConstantValueAttribute.cs b/JavaAsm/CustomAttributes/ConstantValueAttribute.cs index a2048ed..ebb1027 100644 --- a/JavaAsm/CustomAttributes/ConstantValueAttribute.cs +++ b/JavaAsm/CustomAttributes/ConstantValueAttribute.cs @@ -4,45 +4,61 @@ using JavaAsm.IO; using JavaAsm.IO.ConstantPoolEntries; -namespace JavaAsm.CustomAttributes -{ - public class ConstantValueAttribute : CustomAttribute - { +namespace JavaAsm.CustomAttributes { + public class ConstantValueAttribute : CustomAttribute { public object Value { get; set; } - internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) - { - var result = new byte[2]; - Binary.BigEndian.Set(Value switch - { - long longValue => writerState.ConstantPool.Find(new LongEntry(longValue)), - float floatValue => writerState.ConstantPool.Find(new FloatEntry(floatValue)), - double doubleValue => writerState.ConstantPool.Find(new DoubleEntry(doubleValue)), - int integerValue => writerState.ConstantPool.Find(new IntegerEntry(integerValue)), - string stringValue => writerState.ConstantPool.Find(new StringEntry(new Utf8Entry(stringValue))), - _ => throw new ArgumentOutOfRangeException(nameof(Value), $"Can't encode value of type {Value.GetType()}") - }, result); + internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) { + ushort value; + switch (this.Value) { + case long longValue: + value = writerState.ConstantPool.Find(new LongEntry(longValue)); + break; + case float floatValue: + value = writerState.ConstantPool.Find(new FloatEntry(floatValue)); + break; + case double doubleValue: + value = writerState.ConstantPool.Find(new DoubleEntry(doubleValue)); + break; + case int integerValue: + value = writerState.ConstantPool.Find(new IntegerEntry(integerValue)); + break; + case string stringValue: + value = writerState.ConstantPool.Find(new StringEntry(new Utf8Entry(stringValue))); + break; + default: throw new ArgumentOutOfRangeException(nameof(this.Value), $"Can't encode value of type {this.Value.GetType()}"); + } + + byte[] result = new byte[2]; + Binary.BigEndian.Set(value, result); return result; } } - internal class ConstantValueAttributeFactory : ICustomAttributeFactory - { - public ConstantValueAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) - { - var entry = readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(attributeDataStream)); - return new ConstantValueAttribute { - Value = entry switch - { - LongEntry longEntry => (longEntry.Value as object), - FloatEntry floatEntry => floatEntry.Value, - DoubleEntry doubleEntry => doubleEntry.Value, - IntegerEntry integerEntry => integerEntry.Value, - StringEntry stringEntry => stringEntry.Value.String, - _ => throw new ArgumentOutOfRangeException(nameof(entry), - $"Can't use constant pool entry of type {entry.GetType()} as constant value") - } - }; + internal class ConstantValueAttributeFactory : ICustomAttributeFactory { + public ConstantValueAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) { + Entry entry = readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(attributeDataStream)); + object value; + switch (entry) { + case LongEntry longEntry: + value = longEntry.Value; + break; + case FloatEntry floatEntry: + value = floatEntry.Value; + break; + case DoubleEntry doubleEntry: + value = doubleEntry.Value; + break; + case IntegerEntry integerEntry: + value = integerEntry.Value; + break; + case StringEntry stringEntry: + value = stringEntry.Value.String; + break; + default: throw new ArgumentOutOfRangeException(nameof(entry), $"Can't use constant pool entry of type {entry.GetType()} as constant value"); + } + + return new ConstantValueAttribute {Value = value}; } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/DeprecatedAttribute.cs b/JavaAsm/CustomAttributes/DeprecatedAttribute.cs index 6f1a867..bf2e04b 100644 --- a/JavaAsm/CustomAttributes/DeprecatedAttribute.cs +++ b/JavaAsm/CustomAttributes/DeprecatedAttribute.cs @@ -1,15 +1,12 @@ using System.IO; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes -{ - public class DeprecatedAttribute : CustomAttribute - { +namespace JavaAsm.CustomAttributes { + public class DeprecatedAttribute : CustomAttribute { internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) => new byte[0]; } - internal class DeprecatedAttributeFactory : ICustomAttributeFactory - { + internal class DeprecatedAttributeFactory : ICustomAttributeFactory { public DeprecatedAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) => new DeprecatedAttribute(); } } \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/EnclosingMethodAttribute.cs b/JavaAsm/CustomAttributes/EnclosingMethodAttribute.cs index 9b40f50..ec960b4 100644 --- a/JavaAsm/CustomAttributes/EnclosingMethodAttribute.cs +++ b/JavaAsm/CustomAttributes/EnclosingMethodAttribute.cs @@ -3,57 +3,48 @@ using JavaAsm.IO; using JavaAsm.IO.ConstantPoolEntries; -namespace JavaAsm.CustomAttributes -{ - public class EnclosingMethodAttribute : CustomAttribute - { +namespace JavaAsm.CustomAttributes { + public class EnclosingMethodAttribute : CustomAttribute { public ClassName Class { get; set; } public string MethodName { get; set; } public MethodDescriptor MethodDescriptor { get; set; } - internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) - { - using var attributeDataStream = new MemoryStream(); + internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) { + MemoryStream attributeDataStream = new MemoryStream(); Binary.BigEndian.Write(attributeDataStream, - writerState.ConstantPool.Find(new ClassEntry(new Utf8Entry(Class.Name)))); + writerState.ConstantPool.Find(new ClassEntry(new Utf8Entry(this.Class.Name)))); - if (MethodName == null && MethodDescriptor == null) - { + if (this.MethodName == null && this.MethodDescriptor == null) { Binary.BigEndian.Write(attributeDataStream, (ushort) 0); - } - else - { + } + else { Binary.BigEndian.Write(attributeDataStream, - writerState.ConstantPool.Find(new NameAndTypeEntry(new Utf8Entry(MethodName), - new Utf8Entry(MethodDescriptor.ToString())))); + writerState.ConstantPool.Find(new NameAndTypeEntry(new Utf8Entry(this.MethodName), + new Utf8Entry(this.MethodDescriptor.ToString())))); } return attributeDataStream.ToArray(); } } - internal class EnclosingMethodAttributeFactory : ICustomAttributeFactory - { - public EnclosingMethodAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) - { - var attribute = new EnclosingMethodAttribute - { - Class = new ClassName(readerState.ConstantPool - .GetEntry(Binary.BigEndian.ReadUInt16(attributeDataStream)).Name.String) + internal class EnclosingMethodAttributeFactory : ICustomAttributeFactory { + public EnclosingMethodAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) { + EnclosingMethodAttribute attribute = new EnclosingMethodAttribute { + Class = new ClassName(readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(attributeDataStream)).Name.String) }; - var nameAndTypeEntryIndex = Binary.BigEndian.ReadUInt16(attributeDataStream); + ushort nameAndTypeEntryIndex = Binary.BigEndian.ReadUInt16(attributeDataStream); - if (nameAndTypeEntryIndex == 0) + if (nameAndTypeEntryIndex == 0) return attribute; - var nameAndTypeEntry = readerState.ConstantPool.GetEntry(nameAndTypeEntryIndex); + NameAndTypeEntry nameAndTypeEntry = readerState.ConstantPool.GetEntry(nameAndTypeEntryIndex); attribute.MethodName = nameAndTypeEntry.Name.String; attribute.MethodDescriptor = MethodDescriptor.Parse(nameAndTypeEntry.Descriptor.String); return attribute; } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/ExceptionsAttribute.cs b/JavaAsm/CustomAttributes/ExceptionsAttribute.cs index ad0505d..32c1f21 100644 --- a/JavaAsm/CustomAttributes/ExceptionsAttribute.cs +++ b/JavaAsm/CustomAttributes/ExceptionsAttribute.cs @@ -5,21 +5,18 @@ using JavaAsm.IO; using JavaAsm.IO.ConstantPoolEntries; -namespace JavaAsm.CustomAttributes -{ - public class ExceptionsAttribute : CustomAttribute - { +namespace JavaAsm.CustomAttributes { + public class ExceptionsAttribute : CustomAttribute { public List ExceptionTable { get; set; } = new List(); - internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) - { - using var attributeDataStream = new MemoryStream(); + internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) { + MemoryStream attributeDataStream = new MemoryStream(); - if (ExceptionTable.Count > ushort.MaxValue) - throw new ArgumentOutOfRangeException(nameof(ExceptionTable.Count), - $"Exception table size too big: {ExceptionTable.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(attributeDataStream, (ushort) ExceptionTable.Count); - foreach (var exceptionClassName in ExceptionTable) + if (this.ExceptionTable.Count > ushort.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.ExceptionTable.Count), + $"Exception table size too big: {this.ExceptionTable.Count} > {ushort.MaxValue}"); + Binary.BigEndian.Write(attributeDataStream, (ushort) this.ExceptionTable.Count); + foreach (ClassName exceptionClassName in this.ExceptionTable) Binary.BigEndian.Write(attributeDataStream, writerState.ConstantPool.Find(new ClassEntry(new Utf8Entry(exceptionClassName.Name)))); @@ -27,19 +24,16 @@ internal override byte[] Save(ClassWriterState writerState, AttributeScope scope } } - internal class ExceptionsAttributeFactory : ICustomAttributeFactory - { - public ExceptionsAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) - { - var attribute = new ExceptionsAttribute(); + internal class ExceptionsAttributeFactory : ICustomAttributeFactory { + public ExceptionsAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) { + ExceptionsAttribute attribute = new ExceptionsAttribute(); - var count = Binary.BigEndian.ReadUInt16(attributeDataStream); + ushort count = Binary.BigEndian.ReadUInt16(attributeDataStream); attribute.ExceptionTable.Capacity = count; - for (var i = 0; i < count; i++) - attribute.ExceptionTable.Add(new ClassName(readerState.ConstantPool - .GetEntry(Binary.BigEndian.ReadUInt16(attributeDataStream)).Name.String)); + for (int i = 0; i < count; i++) + attribute.ExceptionTable.Add(new ClassName(readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(attributeDataStream)).Name.String)); return attribute; } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/InnerClassesAttribute.cs b/JavaAsm/CustomAttributes/InnerClassesAttribute.cs index 4514c3f..c593189 100644 --- a/JavaAsm/CustomAttributes/InnerClassesAttribute.cs +++ b/JavaAsm/CustomAttributes/InnerClassesAttribute.cs @@ -5,27 +5,21 @@ using JavaAsm.IO; using JavaAsm.IO.ConstantPoolEntries; -namespace JavaAsm.CustomAttributes -{ - public class InnerClassesAttribute : CustomAttribute - { +namespace JavaAsm.CustomAttributes { + public class InnerClassesAttribute : CustomAttribute { public List Classes { get; set; } = new List(); - internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) - { - using var attributeDataStream = new MemoryStream(); + internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) { + MemoryStream attributeDataStream = new MemoryStream(); - if (Classes.Count > ushort.MaxValue) - throw new ArgumentOutOfRangeException(nameof(Classes.Count), $"Too many inner classes: {Classes.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(attributeDataStream, (ushort)Classes.Count); - foreach (var innerClass in Classes) - { + if (this.Classes.Count > ushort.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.Classes.Count), $"Too many inner classes: {this.Classes.Count} > {ushort.MaxValue}"); + Binary.BigEndian.Write(attributeDataStream, (ushort) this.Classes.Count); + foreach (InnerClass innerClass in this.Classes) { Binary.BigEndian.Write(attributeDataStream, writerState.ConstantPool.Find(new ClassEntry(new Utf8Entry(innerClass.InnerClassName.Name)))); - Binary.BigEndian.Write(attributeDataStream, innerClass.OuterClassName == null ? (ushort) 0 : - writerState.ConstantPool.Find(new ClassEntry(new Utf8Entry(innerClass.OuterClassName.Name)))); - Binary.BigEndian.Write(attributeDataStream, innerClass.InnerName == null ? (ushort) 0 : - writerState.ConstantPool.Find(new Utf8Entry(innerClass.InnerName))); + Binary.BigEndian.Write(attributeDataStream, innerClass.OuterClassName == null ? (ushort) 0 : writerState.ConstantPool.Find(new ClassEntry(new Utf8Entry(innerClass.OuterClassName.Name)))); + Binary.BigEndian.Write(attributeDataStream, innerClass.InnerName == null ? (ushort) 0 : writerState.ConstantPool.Find(new Utf8Entry(innerClass.InnerName))); Binary.BigEndian.Write(attributeDataStream, (ushort) innerClass.Access); } @@ -33,8 +27,7 @@ internal override byte[] Save(ClassWriterState writerState, AttributeScope scope } } - public class InnerClass - { + public class InnerClass { public ClassName InnerClassName { get; set; } public ClassName OuterClassName { get; set; } @@ -43,35 +36,27 @@ public class InnerClass public ClassAccessModifiers Access { get; set; } - public override string ToString() - { - return $"{AccessModifiersExtensions.ToString(Access)} {InnerClassName?.ToString() ?? "null"} {OuterClassName?.ToString() ?? "null"} {InnerName?.ToString() ?? "null"}"; + public override string ToString() { + return $"{AccessModifiersExtensions.ToString(this.Access)} {this.InnerClassName?.ToString() ?? "null"} {this.OuterClassName?.ToString() ?? "null"} {this.InnerName?.ToString() ?? "null"}"; } } - internal class InnerClassesAttributeFactory : ICustomAttributeFactory - { - public InnerClassesAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) - { - var attribute = new InnerClassesAttribute(); + internal class InnerClassesAttributeFactory : ICustomAttributeFactory { + public InnerClassesAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) { + InnerClassesAttribute attribute = new InnerClassesAttribute(); - var classesCount = Binary.BigEndian.ReadUInt16(attributeDataStream); + ushort classesCount = Binary.BigEndian.ReadUInt16(attributeDataStream); attribute.Classes.Capacity = classesCount; - for (var i = 0; i < classesCount; i++) - { - var innerClass = new InnerClass - { - InnerClassName = new ClassName(readerState.ConstantPool - .GetEntry(Binary.BigEndian.ReadUInt16(attributeDataStream)).Name.String) + for (int i = 0; i < classesCount; i++) { + InnerClass innerClass = new InnerClass { + InnerClassName = new ClassName(readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(attributeDataStream)).Name.String) }; - var outerClassIndex = Binary.BigEndian.ReadUInt16(attributeDataStream); + ushort outerClassIndex = Binary.BigEndian.ReadUInt16(attributeDataStream); if (outerClassIndex != 0) - innerClass.OuterClassName = new ClassName(readerState.ConstantPool - .GetEntry(outerClassIndex).Name.String); - var innerNameIndex = Binary.BigEndian.ReadUInt16(attributeDataStream); + innerClass.OuterClassName = new ClassName(readerState.ConstantPool.GetEntry(outerClassIndex).Name.String); + ushort innerNameIndex = Binary.BigEndian.ReadUInt16(attributeDataStream); if (innerNameIndex != 0) - innerClass.InnerName = readerState.ConstantPool - .GetEntry(innerNameIndex).String; + innerClass.InnerName = readerState.ConstantPool.GetEntry(innerNameIndex).String; innerClass.Access = (ClassAccessModifiers) Binary.BigEndian.ReadUInt16(attributeDataStream); attribute.Classes.Add(innerClass); } @@ -79,4 +64,4 @@ public InnerClassesAttribute Parse(Stream attributeDataStream, uint attributeDat return attribute; } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/LineNumberTableAttribute.cs b/JavaAsm/CustomAttributes/LineNumberTableAttribute.cs index a40d814..a973399 100644 --- a/JavaAsm/CustomAttributes/LineNumberTableAttribute.cs +++ b/JavaAsm/CustomAttributes/LineNumberTableAttribute.cs @@ -4,12 +4,9 @@ using BinaryEncoding; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes -{ - public class LineNumberTableAttribute : CustomAttribute - { - public class LineNumberTableEntry - { +namespace JavaAsm.CustomAttributes { + public class LineNumberTableAttribute : CustomAttribute { + public class LineNumberTableEntry { public ushort StartPc { get; set; } public ushort LineNumber { get; set; } @@ -17,15 +14,13 @@ public class LineNumberTableEntry public List LineNumberTable { get; set; } = new List(); - internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) - { - using var attributeDataStream = new MemoryStream(); + internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) { + MemoryStream attributeDataStream = new MemoryStream(); - if (LineNumberTable.Count > ushort.MaxValue) - throw new ArgumentOutOfRangeException(nameof(LineNumberTable.Count), $"Line number table too big: {LineNumberTable.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(attributeDataStream, (ushort)LineNumberTable.Count); - foreach (var exceptionTableEntry in LineNumberTable) - { + if (this.LineNumberTable.Count > ushort.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.LineNumberTable.Count), $"Line number table too big: {this.LineNumberTable.Count} > {ushort.MaxValue}"); + Binary.BigEndian.Write(attributeDataStream, (ushort) this.LineNumberTable.Count); + foreach (LineNumberTableEntry exceptionTableEntry in this.LineNumberTable) { Binary.BigEndian.Write(attributeDataStream, exceptionTableEntry.StartPc); Binary.BigEndian.Write(attributeDataStream, exceptionTableEntry.LineNumber); } @@ -34,17 +29,14 @@ internal override byte[] Save(ClassWriterState writerState, AttributeScope scope } } - internal class LineNumberTableAttributeFactory : ICustomAttributeFactory - { - public LineNumberTableAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) - { - var attribute = new LineNumberTableAttribute(); + internal class LineNumberTableAttributeFactory : ICustomAttributeFactory { + public LineNumberTableAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) { + LineNumberTableAttribute attribute = new LineNumberTableAttribute(); - var exceptionTableSize = Binary.BigEndian.ReadUInt16(attributeDataStream); + ushort exceptionTableSize = Binary.BigEndian.ReadUInt16(attributeDataStream); attribute.LineNumberTable.Capacity = exceptionTableSize; - for (var i = 0; i < exceptionTableSize; i++) - attribute.LineNumberTable.Add(new LineNumberTableAttribute.LineNumberTableEntry - { + for (int i = 0; i < exceptionTableSize; i++) + attribute.LineNumberTable.Add(new LineNumberTableAttribute.LineNumberTableEntry { StartPc = Binary.BigEndian.ReadUInt16(attributeDataStream), LineNumber = Binary.BigEndian.ReadUInt16(attributeDataStream) }); @@ -52,4 +44,4 @@ public LineNumberTableAttribute Parse(Stream attributeDataStream, uint attribute return attribute; } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/LocalVariableTableAttribute.cs b/JavaAsm/CustomAttributes/LocalVariableTableAttribute.cs index 4d1ceab..7b881ba 100644 --- a/JavaAsm/CustomAttributes/LocalVariableTableAttribute.cs +++ b/JavaAsm/CustomAttributes/LocalVariableTableAttribute.cs @@ -1,16 +1,14 @@ using System; using System.Collections.Generic; using System.IO; +using System.Runtime.CompilerServices; using BinaryEncoding; using JavaAsm.IO; using JavaAsm.IO.ConstantPoolEntries; -namespace JavaAsm.CustomAttributes -{ - public class LocalVariableTableAttribute : CustomAttribute - { - public class LocalVariableTableEntry - { +namespace JavaAsm.CustomAttributes { + public class LocalVariableTableAttribute : CustomAttribute { + public class LocalVariableTableEntry { public ushort StartPc { get; set; } public ushort Length { get; set; } @@ -20,19 +18,19 @@ public class LocalVariableTableEntry public TypeDescriptor Descriptor { get; set; } public ushort Index { get; set; } + + public uint EndPC => (uint) this.StartPc + (uint) this.Length; } public List LocalVariableTable { get; set; } = new List(); - internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) - { - using var attributeDataStream = new MemoryStream(); + internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) { + MemoryStream attributeDataStream = new MemoryStream(); - if (LocalVariableTable.Count > ushort.MaxValue) - throw new ArgumentOutOfRangeException(nameof(LocalVariableTable.Count), $"Local variable table is too big: {LocalVariableTable.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(attributeDataStream, (ushort) LocalVariableTable.Count); - foreach (var localVariableTableEntry in LocalVariableTable) - { + if (this.LocalVariableTable.Count > ushort.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.LocalVariableTable.Count), $"Local variable table is too big: {this.LocalVariableTable.Count} > {ushort.MaxValue}"); + Binary.BigEndian.Write(attributeDataStream, (ushort) this.LocalVariableTable.Count); + foreach (LocalVariableTableEntry localVariableTableEntry in this.LocalVariableTable) { Binary.BigEndian.Write(attributeDataStream, localVariableTableEntry.StartPc); Binary.BigEndian.Write(attributeDataStream, localVariableTableEntry.Length); Binary.BigEndian.Write(attributeDataStream, @@ -46,17 +44,14 @@ internal override byte[] Save(ClassWriterState writerState, AttributeScope scope } } - internal class LocalVariableTableAttributeFactory : ICustomAttributeFactory - { - public LocalVariableTableAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) - { - var attribute = new LocalVariableTableAttribute(); + internal class LocalVariableTableAttributeFactory : ICustomAttributeFactory { + public LocalVariableTableAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) { + LocalVariableTableAttribute attribute = new LocalVariableTableAttribute(); - var localVariableTableSize = Binary.BigEndian.ReadUInt16(attributeDataStream); + ushort localVariableTableSize = Binary.BigEndian.ReadUInt16(attributeDataStream); attribute.LocalVariableTable.Capacity = localVariableTableSize; - for (var i = 0; i < localVariableTableSize; i++) - attribute.LocalVariableTable.Add(new LocalVariableTableAttribute.LocalVariableTableEntry - { + for (int i = 0; i < localVariableTableSize; i++) + attribute.LocalVariableTable.Add(new LocalVariableTableAttribute.LocalVariableTableEntry { StartPc = Binary.BigEndian.ReadUInt16(attributeDataStream), Length = Binary.BigEndian.ReadUInt16(attributeDataStream), Name = readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(attributeDataStream)).String, @@ -67,4 +62,4 @@ public LocalVariableTableAttribute Parse(Stream attributeDataStream, uint attrib return attribute; } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/LocalVariableTypeTableAttribute.cs b/JavaAsm/CustomAttributes/LocalVariableTypeTableAttribute.cs index c06e34c..09e43bb 100644 --- a/JavaAsm/CustomAttributes/LocalVariableTypeTableAttribute.cs +++ b/JavaAsm/CustomAttributes/LocalVariableTypeTableAttribute.cs @@ -5,16 +5,15 @@ using JavaAsm.IO; using JavaAsm.IO.ConstantPoolEntries; -namespace JavaAsm.CustomAttributes -{ - public class LocalVariableTypeTableAttribute : CustomAttribute - { - public class LocalVariableTypeTableEntry - { +namespace JavaAsm.CustomAttributes { + public class LocalVariableTypeTableAttribute : CustomAttribute { + public class LocalVariableTypeTableEntry { public ushort StartPc { get; set; } public ushort Length { get; set; } - + + public uint EndPC => (uint) this.StartPc + (uint) this.Length; + public string Name { get; set; } public string Signature { get; set; } @@ -24,15 +23,13 @@ public class LocalVariableTypeTableEntry public List LocalVariableTypeTable { get; set; } = new List(); - internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) - { - using var attributeDataStream = new MemoryStream(); + internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) { + MemoryStream attributeDataStream = new MemoryStream(); - if (LocalVariableTypeTable.Count > ushort.MaxValue) - throw new ArgumentOutOfRangeException(nameof(LocalVariableTypeTable.Count), $"Local variable type table is too big: {LocalVariableTypeTable.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(attributeDataStream, (ushort)LocalVariableTypeTable.Count); - foreach (var localVariableTypeTableEntry in LocalVariableTypeTable) - { + if (this.LocalVariableTypeTable.Count > ushort.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.LocalVariableTypeTable.Count), $"Local variable type table is too big: {this.LocalVariableTypeTable.Count} > {ushort.MaxValue}"); + Binary.BigEndian.Write(attributeDataStream, (ushort) this.LocalVariableTypeTable.Count); + foreach (LocalVariableTypeTableEntry localVariableTypeTableEntry in this.LocalVariableTypeTable) { Binary.BigEndian.Write(attributeDataStream, localVariableTypeTableEntry.StartPc); Binary.BigEndian.Write(attributeDataStream, localVariableTypeTableEntry.Length); Binary.BigEndian.Write(attributeDataStream, @@ -46,17 +43,14 @@ internal override byte[] Save(ClassWriterState writerState, AttributeScope scope } } - internal class LocalVariableTypeTableAttributeFactory : ICustomAttributeFactory - { - public LocalVariableTypeTableAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) - { - var attribute = new LocalVariableTypeTableAttribute(); + internal class LocalVariableTypeTableAttributeFactory : ICustomAttributeFactory { + public LocalVariableTypeTableAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) { + LocalVariableTypeTableAttribute attribute = new LocalVariableTypeTableAttribute(); - var localVariableTypeTableSize = Binary.BigEndian.ReadUInt16(attributeDataStream); + ushort localVariableTypeTableSize = Binary.BigEndian.ReadUInt16(attributeDataStream); attribute.LocalVariableTypeTable.Capacity = localVariableTypeTableSize; - for (var i = 0; i < localVariableTypeTableSize; i++) - attribute.LocalVariableTypeTable.Add(new LocalVariableTypeTableAttribute.LocalVariableTypeTableEntry - { + for (int i = 0; i < localVariableTypeTableSize; i++) + attribute.LocalVariableTypeTable.Add(new LocalVariableTypeTableAttribute.LocalVariableTypeTableEntry { StartPc = Binary.BigEndian.ReadUInt16(attributeDataStream), Length = Binary.BigEndian.ReadUInt16(attributeDataStream), Name = readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(attributeDataStream)).String, @@ -67,4 +61,4 @@ public LocalVariableTypeTableAttribute Parse(Stream attributeDataStream, uint at return attribute; } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/MethodParametersAttribute.cs b/JavaAsm/CustomAttributes/MethodParametersAttribute.cs index d22dcb3..4e5fe04 100644 --- a/JavaAsm/CustomAttributes/MethodParametersAttribute.cs +++ b/JavaAsm/CustomAttributes/MethodParametersAttribute.cs @@ -6,12 +6,9 @@ using JavaAsm.IO; using JavaAsm.IO.ConstantPoolEntries; -namespace JavaAsm.CustomAttributes -{ - public class MethodParametersAttribute : CustomAttribute - { - public class Parameter - { +namespace JavaAsm.CustomAttributes { + public class MethodParametersAttribute : CustomAttribute { + public class Parameter { public string Name { get; set; } public ClassAccessModifiers Access { get; set; } @@ -19,15 +16,13 @@ public class Parameter public List Parameters { get; set; } = new List(); - internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) - { - using var attributeDataStream = new MemoryStream(); + internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) { + MemoryStream attributeDataStream = new MemoryStream(); - if (Parameters.Count > byte.MaxValue) - throw new ArgumentOutOfRangeException(nameof(Parameters.Count), $"Too many parameters: {Parameters.Count} > {byte.MaxValue}"); - attributeDataStream.WriteByte((byte) Parameters.Count); - foreach (var parameter in Parameters) - { + if (this.Parameters.Count > byte.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.Parameters.Count), $"Too many parameters: {this.Parameters.Count} > {byte.MaxValue}"); + attributeDataStream.WriteByte((byte) this.Parameters.Count); + foreach (Parameter parameter in this.Parameters) { Binary.BigEndian.Write(attributeDataStream, writerState.ConstantPool.Find(new Utf8Entry(parameter.Name))); Binary.BigEndian.Write(attributeDataStream, (ushort) parameter.Access); @@ -37,17 +32,14 @@ internal override byte[] Save(ClassWriterState writerState, AttributeScope scope } } - internal class MethodParametersAttributeFactory : ICustomAttributeFactory - { - public MethodParametersAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) - { - var attribute = new MethodParametersAttribute(); + internal class MethodParametersAttributeFactory : ICustomAttributeFactory { + public MethodParametersAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) { + MethodParametersAttribute attribute = new MethodParametersAttribute(); - var exceptionTableSize = attributeDataStream.ReadByteFully(); + byte exceptionTableSize = attributeDataStream.ReadByteFully(); attribute.Parameters.Capacity = exceptionTableSize; - for (var i = 0; i < exceptionTableSize; i++) - attribute.Parameters.Add(new MethodParametersAttribute.Parameter - { + for (int i = 0; i < exceptionTableSize; i++) + attribute.Parameters.Add(new MethodParametersAttribute.Parameter { Name = readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(attributeDataStream)).String, Access = (ClassAccessModifiers) Binary.BigEndian.ReadUInt16(attributeDataStream) }); @@ -55,4 +47,4 @@ public MethodParametersAttribute Parse(Stream attributeDataStream, uint attribut return attribute; } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/RuntimeInvisibleAnnotationsAttribute.cs b/JavaAsm/CustomAttributes/RuntimeInvisibleAnnotationsAttribute.cs index 3ff2067..4fdb6e3 100644 --- a/JavaAsm/CustomAttributes/RuntimeInvisibleAnnotationsAttribute.cs +++ b/JavaAsm/CustomAttributes/RuntimeInvisibleAnnotationsAttribute.cs @@ -5,39 +5,33 @@ using JavaAsm.CustomAttributes.Annotation; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes -{ - public class RuntimeInvisibleAnnotationsAttribute : CustomAttribute - { +namespace JavaAsm.CustomAttributes { + public class RuntimeInvisibleAnnotationsAttribute : CustomAttribute { public List Annotations { get; set; } = new List(); - internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) - { - using var attributeDataStream = new MemoryStream(); + internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) { + MemoryStream attributeDataStream = new MemoryStream(); - if (Annotations.Count > ushort.MaxValue) - throw new ArgumentOutOfRangeException(nameof(Annotations.Count), $"Number of annotations is too big: {Annotations.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(attributeDataStream, (ushort)Annotations.Count); - foreach (var annotation in Annotations) + if (this.Annotations.Count > ushort.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.Annotations.Count), $"Number of annotations is too big: {this.Annotations.Count} > {ushort.MaxValue}"); + Binary.BigEndian.Write(attributeDataStream, (ushort) this.Annotations.Count); + foreach (AnnotationNode annotation in this.Annotations) annotation.Write(attributeDataStream, writerState); return attributeDataStream.ToArray(); } } - internal class RuntimeInvisibleAnnotationsAttributeFactory : ICustomAttributeFactory - { - public RuntimeInvisibleAnnotationsAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) - { - var attribute = new RuntimeInvisibleAnnotationsAttribute(); + internal class RuntimeInvisibleAnnotationsAttributeFactory : ICustomAttributeFactory { + public RuntimeInvisibleAnnotationsAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) { + RuntimeInvisibleAnnotationsAttribute attribute = new RuntimeInvisibleAnnotationsAttribute(); - var annotationsCount = Binary.BigEndian.ReadUInt16(attributeDataStream); + ushort annotationsCount = Binary.BigEndian.ReadUInt16(attributeDataStream); attribute.Annotations.Capacity = annotationsCount; - for (var i = 0; i < annotationsCount; i++) + for (int i = 0; i < annotationsCount; i++) attribute.Annotations.Add(AnnotationNode.Parse(attributeDataStream, readerState)); return attribute; - } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/RuntimeInvisibleParameterAnnotationsAttribute.cs b/JavaAsm/CustomAttributes/RuntimeInvisibleParameterAnnotationsAttribute.cs index fcbf15b..3a517f1 100644 --- a/JavaAsm/CustomAttributes/RuntimeInvisibleParameterAnnotationsAttribute.cs +++ b/JavaAsm/CustomAttributes/RuntimeInvisibleParameterAnnotationsAttribute.cs @@ -6,32 +6,26 @@ using JavaAsm.Helpers; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes -{ - public class ParameterAnnotations - { +namespace JavaAsm.CustomAttributes { + public class ParameterAnnotations { public List Annotations { get; set; } = new List(); } - public class RuntimeInvisibleParameterAnnotationsAttribute : CustomAttribute - { - + public class RuntimeInvisibleParameterAnnotationsAttribute : CustomAttribute { public List Parameters { get; set; } = new List(); - internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) - { - using var attributeDataStream = new MemoryStream(); + internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) { + MemoryStream attributeDataStream = new MemoryStream(); - if (Parameters.Count > byte.MaxValue) - throw new ArgumentOutOfRangeException(nameof(Parameters.Count), $"Number of parameters is too big: {Parameters.Count} > {byte.MaxValue}"); - attributeDataStream.WriteByte((byte)Parameters.Count); - foreach (var parameter in Parameters) - { + if (this.Parameters.Count > byte.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.Parameters.Count), $"Number of parameters is too big: {this.Parameters.Count} > {byte.MaxValue}"); + attributeDataStream.WriteByte((byte) this.Parameters.Count); + foreach (ParameterAnnotations parameter in this.Parameters) { if (parameter.Annotations.Count > ushort.MaxValue) throw new ArgumentOutOfRangeException(nameof(parameter.Annotations.Count), $"Number of annotations is too big: {parameter.Annotations.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(attributeDataStream, (ushort)parameter.Annotations.Count); - foreach (var annotation in parameter.Annotations) + Binary.BigEndian.Write(attributeDataStream, (ushort) parameter.Annotations.Count); + foreach (AnnotationNode annotation in parameter.Annotations) annotation.Write(attributeDataStream, writerState); } @@ -39,20 +33,17 @@ internal override byte[] Save(ClassWriterState writerState, AttributeScope scope } } - internal class RuntimeInvisibleParameterAnnotationsAttributeFactory : ICustomAttributeFactory - { - public RuntimeInvisibleParameterAnnotationsAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) - { - var attribute = new RuntimeInvisibleParameterAnnotationsAttribute(); + internal class RuntimeInvisibleParameterAnnotationsAttributeFactory : ICustomAttributeFactory { + public RuntimeInvisibleParameterAnnotationsAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) { + RuntimeInvisibleParameterAnnotationsAttribute attribute = new RuntimeInvisibleParameterAnnotationsAttribute(); - var parametersCount = attributeDataStream.ReadByteFully(); + byte parametersCount = attributeDataStream.ReadByteFully(); attribute.Parameters.Capacity = parametersCount; - for (var i = 0; i < parametersCount; i++) - { - var parameter = new ParameterAnnotations(); - var annotationsCount = Binary.BigEndian.ReadUInt16(attributeDataStream); + for (int i = 0; i < parametersCount; i++) { + ParameterAnnotations parameter = new ParameterAnnotations(); + ushort annotationsCount = Binary.BigEndian.ReadUInt16(attributeDataStream); parameter.Annotations.Capacity = annotationsCount; - for (var j = 0; j < annotationsCount; j++) + for (int j = 0; j < annotationsCount; j++) parameter.Annotations.Add(AnnotationNode.Parse(attributeDataStream, readerState)); attribute.Parameters.Add(parameter); } @@ -60,4 +51,4 @@ public RuntimeInvisibleParameterAnnotationsAttribute Parse(Stream attributeDataS return attribute; } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/RuntimeInvisibleTypeAnnotationsAttribute.cs b/JavaAsm/CustomAttributes/RuntimeInvisibleTypeAnnotationsAttribute.cs index eea52b5..10cc8ac 100644 --- a/JavaAsm/CustomAttributes/RuntimeInvisibleTypeAnnotationsAttribute.cs +++ b/JavaAsm/CustomAttributes/RuntimeInvisibleTypeAnnotationsAttribute.cs @@ -5,38 +5,33 @@ using JavaAsm.CustomAttributes.TypeAnnotation; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes -{ - public class RuntimeInvisibleTypeAnnotationsAttribute : CustomAttribute - { +namespace JavaAsm.CustomAttributes { + public class RuntimeInvisibleTypeAnnotationsAttribute : CustomAttribute { public List Annotations { get; set; } = new List(); - internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) - { - using var attributeDataStream = new MemoryStream(); + internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) { + MemoryStream attributeDataStream = new MemoryStream(); - if (Annotations.Count > ushort.MaxValue) - throw new ArgumentOutOfRangeException(nameof(Annotations.Count), $"Number of annotations is too big: {Annotations.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(attributeDataStream, (ushort)Annotations.Count); - foreach (var annotation in Annotations) + if (this.Annotations.Count > ushort.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.Annotations.Count), $"Number of annotations is too big: {this.Annotations.Count} > {ushort.MaxValue}"); + Binary.BigEndian.Write(attributeDataStream, (ushort) this.Annotations.Count); + foreach (TypeAnnotationNode annotation in this.Annotations) annotation.Write(attributeDataStream, writerState, scope); return attributeDataStream.ToArray(); } } - internal class RuntimeInvisibleTypeAnnotationsAttributeFactory : ICustomAttributeFactory - { - public RuntimeInvisibleTypeAnnotationsAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) - { - var attribute = new RuntimeInvisibleTypeAnnotationsAttribute(); + internal class RuntimeInvisibleTypeAnnotationsAttributeFactory : ICustomAttributeFactory { + public RuntimeInvisibleTypeAnnotationsAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) { + RuntimeInvisibleTypeAnnotationsAttribute attribute = new RuntimeInvisibleTypeAnnotationsAttribute(); - var annotationsCount = Binary.BigEndian.ReadUInt16(attributeDataStream); + ushort annotationsCount = Binary.BigEndian.ReadUInt16(attributeDataStream); attribute.Annotations.Capacity = annotationsCount; - for (var i = 0; i < annotationsCount; i++) + for (int i = 0; i < annotationsCount; i++) attribute.Annotations.Add(TypeAnnotationNode.Parse(attributeDataStream, readerState, scope)); return attribute; } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/RuntimeVisibleAnnotationsAttribute.cs b/JavaAsm/CustomAttributes/RuntimeVisibleAnnotationsAttribute.cs index 87da637..f3c74fd 100644 --- a/JavaAsm/CustomAttributes/RuntimeVisibleAnnotationsAttribute.cs +++ b/JavaAsm/CustomAttributes/RuntimeVisibleAnnotationsAttribute.cs @@ -5,38 +5,33 @@ using JavaAsm.CustomAttributes.Annotation; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes -{ - public class RuntimeVisibleAnnotationsAttribute : CustomAttribute - { +namespace JavaAsm.CustomAttributes { + public class RuntimeVisibleAnnotationsAttribute : CustomAttribute { public List Annotations { get; set; } = new List(); - internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) - { - using var attributeDataStream = new MemoryStream(); + internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) { + MemoryStream attributeDataStream = new MemoryStream(); - if (Annotations.Count > ushort.MaxValue) - throw new ArgumentOutOfRangeException(nameof(Annotations.Count), $"Number of annotations is too big: {Annotations.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(attributeDataStream, (ushort)Annotations.Count); - foreach (var annotation in Annotations) + if (this.Annotations.Count > ushort.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.Annotations.Count), $"Number of annotations is too big: {this.Annotations.Count} > {ushort.MaxValue}"); + Binary.BigEndian.Write(attributeDataStream, (ushort) this.Annotations.Count); + foreach (AnnotationNode annotation in this.Annotations) annotation.Write(attributeDataStream, writerState); return attributeDataStream.ToArray(); } } - internal class RuntimeVisibleAnnotationsAttributeFactory : ICustomAttributeFactory - { - public RuntimeVisibleAnnotationsAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) - { - var attribute = new RuntimeVisibleAnnotationsAttribute(); + internal class RuntimeVisibleAnnotationsAttributeFactory : ICustomAttributeFactory { + public RuntimeVisibleAnnotationsAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) { + RuntimeVisibleAnnotationsAttribute attribute = new RuntimeVisibleAnnotationsAttribute(); - var annotationsCount = Binary.BigEndian.ReadUInt16(attributeDataStream); + ushort annotationsCount = Binary.BigEndian.ReadUInt16(attributeDataStream); attribute.Annotations.Capacity = annotationsCount; - for (var i = 0; i < annotationsCount; i++) + for (int i = 0; i < annotationsCount; i++) attribute.Annotations.Add(AnnotationNode.Parse(attributeDataStream, readerState)); return attribute; } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/RuntimeVisibleParameterAnnotationsAttribute.cs b/JavaAsm/CustomAttributes/RuntimeVisibleParameterAnnotationsAttribute.cs index 4ee7947..1045fb8 100644 --- a/JavaAsm/CustomAttributes/RuntimeVisibleParameterAnnotationsAttribute.cs +++ b/JavaAsm/CustomAttributes/RuntimeVisibleParameterAnnotationsAttribute.cs @@ -6,26 +6,22 @@ using JavaAsm.Helpers; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes -{ - public class RuntimeVisibleParameterAnnotationsAttribute : CustomAttribute - { +namespace JavaAsm.CustomAttributes { + public class RuntimeVisibleParameterAnnotationsAttribute : CustomAttribute { public List Parameters { get; set; } = new List(); - internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) - { - using var attributeDataStream = new MemoryStream(); + internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) { + MemoryStream attributeDataStream = new MemoryStream(); - if (Parameters.Count > byte.MaxValue) - throw new ArgumentOutOfRangeException(nameof(Parameters.Count), $"Number of parameters is too big: {Parameters.Count} > {byte.MaxValue}"); - attributeDataStream.WriteByte((byte)Parameters.Count); - foreach (var parameter in Parameters) - { + if (this.Parameters.Count > byte.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.Parameters.Count), $"Number of parameters is too big: {this.Parameters.Count} > {byte.MaxValue}"); + attributeDataStream.WriteByte((byte) this.Parameters.Count); + foreach (ParameterAnnotations parameter in this.Parameters) { if (parameter.Annotations.Count > ushort.MaxValue) throw new ArgumentOutOfRangeException(nameof(parameter.Annotations.Count), $"Number of annotations is too big: {parameter.Annotations.Count} > {ushort.MaxValue}"); Binary.BigEndian.Write(attributeDataStream, (ushort) parameter.Annotations.Count); - foreach (var annotation in parameter.Annotations) + foreach (AnnotationNode annotation in parameter.Annotations) annotation.Write(attributeDataStream, writerState); } @@ -33,20 +29,17 @@ internal override byte[] Save(ClassWriterState writerState, AttributeScope scope } } - internal class RuntimeVisibleParameterAnnotationsAttributeFactory : ICustomAttributeFactory - { - public RuntimeVisibleParameterAnnotationsAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) - { - var attribute = new RuntimeVisibleParameterAnnotationsAttribute(); + internal class RuntimeVisibleParameterAnnotationsAttributeFactory : ICustomAttributeFactory { + public RuntimeVisibleParameterAnnotationsAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) { + RuntimeVisibleParameterAnnotationsAttribute attribute = new RuntimeVisibleParameterAnnotationsAttribute(); - var parametersCount = attributeDataStream.ReadByteFully(); + byte parametersCount = attributeDataStream.ReadByteFully(); attribute.Parameters.Capacity = parametersCount; - for (var i = 0; i < parametersCount; i++) - { - var parameter = new ParameterAnnotations(); - var annotationsCount = Binary.BigEndian.ReadUInt16(attributeDataStream); + for (int i = 0; i < parametersCount; i++) { + ParameterAnnotations parameter = new ParameterAnnotations(); + ushort annotationsCount = Binary.BigEndian.ReadUInt16(attributeDataStream); parameter.Annotations.Capacity = annotationsCount; - for (var j = 0; j < annotationsCount; j++) + for (int j = 0; j < annotationsCount; j++) parameter.Annotations.Add(AnnotationNode.Parse(attributeDataStream, readerState)); attribute.Parameters.Add(parameter); } @@ -54,4 +47,4 @@ public RuntimeVisibleParameterAnnotationsAttribute Parse(Stream attributeDataStr return attribute; } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/RuntimeVisibleTypeAnnotationsAttribute.cs b/JavaAsm/CustomAttributes/RuntimeVisibleTypeAnnotationsAttribute.cs index 67c8dd8..558916f 100644 --- a/JavaAsm/CustomAttributes/RuntimeVisibleTypeAnnotationsAttribute.cs +++ b/JavaAsm/CustomAttributes/RuntimeVisibleTypeAnnotationsAttribute.cs @@ -5,38 +5,33 @@ using JavaAsm.CustomAttributes.TypeAnnotation; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes -{ - public class RuntimeVisibleTypeAnnotationsAttribute : CustomAttribute - { +namespace JavaAsm.CustomAttributes { + public class RuntimeVisibleTypeAnnotationsAttribute : CustomAttribute { public List Annotations { get; set; } = new List(); - internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) - { - using var attributeDataStream = new MemoryStream(); + internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) { + using (MemoryStream attributeDataStream = new MemoryStream()) { + if (this.Annotations.Count > ushort.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.Annotations.Count), $"Number of annotations is too big: {this.Annotations.Count} > {ushort.MaxValue}"); + Binary.BigEndian.Write(attributeDataStream, (ushort) this.Annotations.Count); + foreach (TypeAnnotationNode annotation in this.Annotations) + annotation.Write(attributeDataStream, writerState, scope); - if (Annotations.Count > ushort.MaxValue) - throw new ArgumentOutOfRangeException(nameof(Annotations.Count), $"Number of annotations is too big: {Annotations.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(attributeDataStream, (ushort)Annotations.Count); - foreach (var annotation in Annotations) - annotation.Write(attributeDataStream, writerState, scope); - - return attributeDataStream.ToArray(); + return attributeDataStream.ToArray(); + } } } - internal class RuntimeVisibleTypeAnnotationsAttributeFactory : ICustomAttributeFactory - { - public RuntimeVisibleTypeAnnotationsAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) - { - var attribute = new RuntimeVisibleTypeAnnotationsAttribute(); + internal class RuntimeVisibleTypeAnnotationsAttributeFactory : ICustomAttributeFactory { + public RuntimeVisibleTypeAnnotationsAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) { + RuntimeVisibleTypeAnnotationsAttribute attribute = new RuntimeVisibleTypeAnnotationsAttribute(); - var annotationsCount = Binary.BigEndian.ReadUInt16(attributeDataStream); + ushort annotationsCount = Binary.BigEndian.ReadUInt16(attributeDataStream); attribute.Annotations.Capacity = annotationsCount; - for (var i = 0; i < annotationsCount; i++) + for (int i = 0; i < annotationsCount; i++) attribute.Annotations.Add(TypeAnnotationNode.Parse(attributeDataStream, readerState, scope)); return attribute; } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/SignatureAttribute.cs b/JavaAsm/CustomAttributes/SignatureAttribute.cs index 184e647..14222a3 100644 --- a/JavaAsm/CustomAttributes/SignatureAttribute.cs +++ b/JavaAsm/CustomAttributes/SignatureAttribute.cs @@ -3,30 +3,24 @@ using JavaAsm.IO; using JavaAsm.IO.ConstantPoolEntries; -namespace JavaAsm.CustomAttributes -{ - public class SignatureAttribute : CustomAttribute - { +namespace JavaAsm.CustomAttributes { + public class SignatureAttribute : CustomAttribute { public string Value { get; set; } - internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) - { - using var attributeDataStream = new MemoryStream(); + internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) { + MemoryStream attributeDataStream = new MemoryStream(); - Binary.BigEndian.Write(attributeDataStream, writerState.ConstantPool.Find(new Utf8Entry(Value))); + Binary.BigEndian.Write(attributeDataStream, writerState.ConstantPool.Find(new Utf8Entry(this.Value))); return attributeDataStream.ToArray(); } } - internal class SignatureAttributeFactory : ICustomAttributeFactory - { - public SignatureAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) - { - return new SignatureAttribute - { + internal class SignatureAttributeFactory : ICustomAttributeFactory { + public SignatureAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) { + return new SignatureAttribute { Value = readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(attributeDataStream)).String }; } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/SourceDebugExtensionAttribute.cs b/JavaAsm/CustomAttributes/SourceDebugExtensionAttribute.cs index 37b56ca..6e7764f 100644 --- a/JavaAsm/CustomAttributes/SourceDebugExtensionAttribute.cs +++ b/JavaAsm/CustomAttributes/SourceDebugExtensionAttribute.cs @@ -2,26 +2,20 @@ using JavaAsm.Helpers; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes -{ - public class SourceDebugExtensionAttribute : CustomAttribute - { +namespace JavaAsm.CustomAttributes { + public class SourceDebugExtensionAttribute : CustomAttribute { public string Value { get; set; } - internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) - { - return ModifiedUtf8Helper.Encode(Value); + internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) { + return ModifiedUtf8Helper.Encode(this.Value); } } - internal class SourceDebugExtensionFactory : ICustomAttributeFactory - { - public SourceDebugExtensionAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) - { - return new SourceDebugExtensionAttribute - { + internal class SourceDebugExtensionFactory : ICustomAttributeFactory { + public SourceDebugExtensionAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) { + return new SourceDebugExtensionAttribute { Value = ModifiedUtf8Helper.Decode(attributeDataStream.ReadBytes(attributeDataLength)) }; } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/SourceFileAttribute.cs b/JavaAsm/CustomAttributes/SourceFileAttribute.cs index bf0bb61..5af5e8c 100644 --- a/JavaAsm/CustomAttributes/SourceFileAttribute.cs +++ b/JavaAsm/CustomAttributes/SourceFileAttribute.cs @@ -3,30 +3,24 @@ using JavaAsm.IO; using JavaAsm.IO.ConstantPoolEntries; -namespace JavaAsm.CustomAttributes -{ - public class SourceFileAttribute : CustomAttribute - { +namespace JavaAsm.CustomAttributes { + public class SourceFileAttribute : CustomAttribute { public string Value { get; set; } - internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) - { - using var attributeDataStream = new MemoryStream(); + internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) { + MemoryStream attributeDataStream = new MemoryStream(); - Binary.BigEndian.Write(attributeDataStream, writerState.ConstantPool.Find(new Utf8Entry(Value))); + Binary.BigEndian.Write(attributeDataStream, writerState.ConstantPool.Find(new Utf8Entry(this.Value))); return attributeDataStream.ToArray(); } } - internal class SourceFileAttributeFactory : ICustomAttributeFactory - { - public SourceFileAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) - { - return new SourceFileAttribute - { + internal class SourceFileAttributeFactory : ICustomAttributeFactory { + public SourceFileAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) { + return new SourceFileAttribute { Value = readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(attributeDataStream)).String }; } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/StackMapTableAttribute.cs b/JavaAsm/CustomAttributes/StackMapTableAttribute.cs index 69eb509..1d77032 100644 --- a/JavaAsm/CustomAttributes/StackMapTableAttribute.cs +++ b/JavaAsm/CustomAttributes/StackMapTableAttribute.cs @@ -6,12 +6,9 @@ using JavaAsm.IO; using JavaAsm.IO.ConstantPoolEntries; -namespace JavaAsm.CustomAttributes -{ - public class StackMapTableAttribute : CustomAttribute - { - public enum VerificationElementType - { +namespace JavaAsm.CustomAttributes { + public class StackMapTableAttribute : CustomAttribute { + public enum VerificationElementType { Top, Integer, Float, @@ -23,39 +20,33 @@ public enum VerificationElementType Unitialized } - public abstract class VerificationElement - { + public abstract class VerificationElement { public abstract VerificationElementType Type { get; } } - public class SimpleVerificationElement : VerificationElement - { + public class SimpleVerificationElement : VerificationElement { public override VerificationElementType Type { get; } - public SimpleVerificationElement(VerificationElementType type) - { + public SimpleVerificationElement(VerificationElementType type) { type.CheckInAndThrow(nameof(type), VerificationElementType.Top, VerificationElementType.Integer, VerificationElementType.Float, VerificationElementType.Long, VerificationElementType.Double, VerificationElementType.Null, VerificationElementType.UnitializedThis); - Type = type; + this.Type = type; } } - public class ObjectVerificationElement : VerificationElement - { + public class ObjectVerificationElement : VerificationElement { public override VerificationElementType Type => VerificationElementType.Object; public ClassName ObjectClass { get; set; } } - public class UninitializedVerificationElement : VerificationElement - { + public class UninitializedVerificationElement : VerificationElement { public override VerificationElementType Type => VerificationElementType.Unitialized; public ushort NewInstructionOffset { get; set; } } - public enum FrameType - { + public enum FrameType { Same, SameLocals1StackItem, Chop, @@ -63,8 +54,7 @@ public enum FrameType Full } - public class StackMapFrame - { + public class StackMapFrame { public FrameType Type { get; set; } public ushort OffsetDelta { get; set; } @@ -78,11 +68,9 @@ public class StackMapFrame public List Entries { get; set; } = new List(); - internal static void WriteVerificationElement(Stream stream, ClassWriterState writerState, VerificationElement verificationElement) - { + internal static void WriteVerificationElement(Stream stream, ClassWriterState writerState, VerificationElement verificationElement) { stream.WriteByte((byte) verificationElement.Type); - switch (verificationElement) - { + switch (verificationElement) { case ObjectVerificationElement objectVerificationElement: Binary.BigEndian.Write(stream, writerState.ConstantPool.Find( @@ -91,40 +79,34 @@ internal static void WriteVerificationElement(Stream stream, ClassWriterState wr case UninitializedVerificationElement uninitializedVerificationElement: Binary.BigEndian.Write(stream, uninitializedVerificationElement.NewInstructionOffset); break; - case SimpleVerificationElement _: - break; - default: - throw new ArgumentOutOfRangeException(nameof(verificationElement)); + case SimpleVerificationElement _: break; + default: throw new ArgumentOutOfRangeException(nameof(verificationElement)); } } - internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) - { - using var attributeDataStream = new MemoryStream(); + internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) { + MemoryStream attributeDataStream = new MemoryStream(); - if (Entries.Count > ushort.MaxValue) - throw new ArgumentOutOfRangeException(nameof(Entries.Count), $"Too many entries for StackMapTable: {Entries.Count} > {ushort.MaxValue}"); + if (this.Entries.Count > ushort.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.Entries.Count), $"Too many entries for StackMapTable: {this.Entries.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(attributeDataStream, (ushort) Entries.Count); + Binary.BigEndian.Write(attributeDataStream, (ushort) this.Entries.Count); - foreach (var entry in Entries) - { - switch (entry.Type) - { + foreach (StackMapFrame entry in this.Entries) { + switch (entry.Type) { case FrameType.Same: if (entry.OffsetDelta < 64) attributeDataStream.WriteByte((byte) entry.OffsetDelta); - else - { + else { attributeDataStream.WriteByte(251); Binary.BigEndian.Write(attributeDataStream, entry.OffsetDelta); } + break; case FrameType.SameLocals1StackItem: if (entry.OffsetDelta < 64) attributeDataStream.WriteByte((byte) (entry.OffsetDelta + 64)); - else - { + else { attributeDataStream.WriteByte(247); Binary.BigEndian.Write(attributeDataStream, entry.OffsetDelta); } @@ -147,7 +129,7 @@ internal override byte[] Save(ClassWriterState writerState, AttributeScope scope $"Number of locals was < 1 || > 3: {entry.Locals}"); attributeDataStream.WriteByte((byte) (251 + entry.Locals.Count)); Binary.BigEndian.Write(attributeDataStream, entry.OffsetDelta); - foreach (var verificationElement in entry.Locals) + foreach (VerificationElement verificationElement in entry.Locals) WriteVerificationElement(attributeDataStream, writerState, verificationElement); break; case FrameType.Full: @@ -158,18 +140,17 @@ internal override byte[] Save(ClassWriterState writerState, AttributeScope scope throw new ArgumentOutOfRangeException(nameof(entry.Locals.Count), $"Too many entries in frame's locals: {entry.Locals.Count} > {ushort.MaxValue}"); Binary.BigEndian.Write(attributeDataStream, (ushort) entry.Locals.Count); - foreach (var verificationElement in entry.Locals) + foreach (VerificationElement verificationElement in entry.Locals) WriteVerificationElement(attributeDataStream, writerState, verificationElement); if (entry.Stack.Count > ushort.MaxValue) throw new ArgumentOutOfRangeException(nameof(entry.Stack.Count), $"Too many entries in frame's stack: {entry.Stack.Count} > {ushort.MaxValue}"); Binary.BigEndian.Write(attributeDataStream, (ushort) entry.Stack.Count); - foreach (var verificationElement in entry.Stack) + foreach (VerificationElement verificationElement in entry.Stack) WriteVerificationElement(attributeDataStream, writerState, verificationElement); break; - default: - throw new ArgumentOutOfRangeException(nameof(entry.Type)); + default: throw new ArgumentOutOfRangeException(nameof(entry.Type)); } } @@ -177,115 +158,88 @@ internal override byte[] Save(ClassWriterState writerState, AttributeScope scope } } - internal class StackMapTableAttributeFactory : ICustomAttributeFactory - { - private static StackMapTableAttribute.VerificationElement ReadVerificationElement(Stream stream, ClassReaderState readerState) - { - var verificationElementType = (StackMapTableAttribute.VerificationElementType) stream.ReadByteFully(); - return verificationElementType switch - { - StackMapTableAttribute.VerificationElementType.Top => (StackMapTableAttribute.VerificationElement) new StackMapTableAttribute.SimpleVerificationElement(verificationElementType), - StackMapTableAttribute.VerificationElementType.Integer => new StackMapTableAttribute.SimpleVerificationElement(verificationElementType), - StackMapTableAttribute.VerificationElementType.Float => new StackMapTableAttribute.SimpleVerificationElement(verificationElementType), - StackMapTableAttribute.VerificationElementType.Long => new StackMapTableAttribute.SimpleVerificationElement(verificationElementType), - StackMapTableAttribute.VerificationElementType.Double => new StackMapTableAttribute.SimpleVerificationElement(verificationElementType), - StackMapTableAttribute.VerificationElementType.Null => new StackMapTableAttribute.SimpleVerificationElement(verificationElementType), - StackMapTableAttribute.VerificationElementType.UnitializedThis => new StackMapTableAttribute.SimpleVerificationElement(verificationElementType), - StackMapTableAttribute.VerificationElementType.Object => new StackMapTableAttribute.ObjectVerificationElement - { - ObjectClass = new ClassName(readerState.ConstantPool - .GetEntry(Binary.BigEndian.ReadUInt16(stream)) - .Name.String) - }, - StackMapTableAttribute.VerificationElementType.Unitialized => new StackMapTableAttribute.UninitializedVerificationElement - { - NewInstructionOffset = Binary.BigEndian.ReadUInt16(stream) - }, - _ => throw new ArgumentOutOfRangeException(nameof(verificationElementType)) - }; + internal class StackMapTableAttributeFactory : ICustomAttributeFactory { + private static StackMapTableAttribute.VerificationElement ReadVerificationElement(Stream stream, ClassReaderState readerState) { + StackMapTableAttribute.VerificationElementType verificationElementType = (StackMapTableAttribute.VerificationElementType) stream.ReadByteFully(); + switch (verificationElementType) { + case StackMapTableAttribute.VerificationElementType.Top: return new StackMapTableAttribute.SimpleVerificationElement(verificationElementType); + case StackMapTableAttribute.VerificationElementType.Integer: + case StackMapTableAttribute.VerificationElementType.Float: + case StackMapTableAttribute.VerificationElementType.Long: + case StackMapTableAttribute.VerificationElementType.Double: + case StackMapTableAttribute.VerificationElementType.Null: + case StackMapTableAttribute.VerificationElementType.UnitializedThis: + return new StackMapTableAttribute.SimpleVerificationElement(verificationElementType); + case StackMapTableAttribute.VerificationElementType.Object: return new StackMapTableAttribute.ObjectVerificationElement {ObjectClass = new ClassName(readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(stream)).Name.String)}; + case StackMapTableAttribute.VerificationElementType.Unitialized: return new StackMapTableAttribute.UninitializedVerificationElement {NewInstructionOffset = Binary.BigEndian.ReadUInt16(stream)}; + default: throw new ArgumentOutOfRangeException(nameof(verificationElementType)); + } } - public StackMapTableAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) - { - var attribute = new StackMapTableAttribute(); + public StackMapTableAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) { + StackMapTableAttribute attribute = new StackMapTableAttribute(); - var stackMapTableSize = Binary.BigEndian.ReadUInt16(attributeDataStream); + ushort stackMapTableSize = Binary.BigEndian.ReadUInt16(attributeDataStream); attribute.Entries.Capacity = stackMapTableSize; - for (var i = 0; i < stackMapTableSize; i++) - { + for (int i = 0; i < stackMapTableSize; i++) { StackMapTableAttribute.StackMapFrame stackMapFrame; - var frameTypeByte = attributeDataStream.ReadByteFully(); - if (frameTypeByte < 64) - { - stackMapFrame = new StackMapTableAttribute.StackMapFrame - { + byte frameTypeByte = attributeDataStream.ReadByteFully(); + if (frameTypeByte < 64) { + stackMapFrame = new StackMapTableAttribute.StackMapFrame { Type = StackMapTableAttribute.FrameType.Same, OffsetDelta = frameTypeByte }; - } - else if (frameTypeByte < 128) - { - stackMapFrame = new StackMapTableAttribute.StackMapFrame - { + } + else if (frameTypeByte < 128) { + stackMapFrame = new StackMapTableAttribute.StackMapFrame { Type = StackMapTableAttribute.FrameType.SameLocals1StackItem, OffsetDelta = (ushort) (frameTypeByte - 64) }; stackMapFrame.Stack.Add(ReadVerificationElement(attributeDataStream, readerState)); } - else if (frameTypeByte == 247) - { - stackMapFrame = new StackMapTableAttribute.StackMapFrame - { + else if (frameTypeByte == 247) { + stackMapFrame = new StackMapTableAttribute.StackMapFrame { Type = StackMapTableAttribute.FrameType.SameLocals1StackItem, OffsetDelta = Binary.BigEndian.ReadUInt16(attributeDataStream) }; stackMapFrame.Stack.Add(ReadVerificationElement(attributeDataStream, readerState)); } - else if (frameTypeByte < 251) - { - stackMapFrame = new StackMapTableAttribute.StackMapFrame - { + else if (frameTypeByte < 251) { + stackMapFrame = new StackMapTableAttribute.StackMapFrame { Type = StackMapTableAttribute.FrameType.Chop, OffsetDelta = Binary.BigEndian.ReadUInt16(attributeDataStream), ChopK = (byte) (251 - frameTypeByte) }; } - else if (frameTypeByte == 251) - { - stackMapFrame = new StackMapTableAttribute.StackMapFrame - { + else if (frameTypeByte == 251) { + stackMapFrame = new StackMapTableAttribute.StackMapFrame { Type = StackMapTableAttribute.FrameType.Same, OffsetDelta = Binary.BigEndian.ReadUInt16(attributeDataStream) }; } - else if (frameTypeByte < 255) - { - stackMapFrame = new StackMapTableAttribute.StackMapFrame - { + else if (frameTypeByte < 255) { + stackMapFrame = new StackMapTableAttribute.StackMapFrame { Type = StackMapTableAttribute.FrameType.Append, OffsetDelta = Binary.BigEndian.ReadUInt16(attributeDataStream) }; - for (var j = 0; j < frameTypeByte - 251; j++) - { + for (int j = 0; j < frameTypeByte - 251; j++) { stackMapFrame.Locals.Add(ReadVerificationElement(attributeDataStream, readerState)); } } - else if (frameTypeByte == 255) - { - stackMapFrame = new StackMapTableAttribute.StackMapFrame - { + else if (frameTypeByte == 255) { + stackMapFrame = new StackMapTableAttribute.StackMapFrame { Type = StackMapTableAttribute.FrameType.Full, OffsetDelta = Binary.BigEndian.ReadUInt16(attributeDataStream) }; - var localsCount = Binary.BigEndian.ReadUInt16(attributeDataStream); - for (var j = 0; j < localsCount; j++) + ushort localsCount = Binary.BigEndian.ReadUInt16(attributeDataStream); + for (int j = 0; j < localsCount; j++) stackMapFrame.Locals.Add(ReadVerificationElement(attributeDataStream, readerState)); - var stackCount = Binary.BigEndian.ReadUInt16(attributeDataStream); - for (var j = 0; j < stackCount; j++) + ushort stackCount = Binary.BigEndian.ReadUInt16(attributeDataStream); + for (int j = 0; j < stackCount; j++) stackMapFrame.Stack.Add(ReadVerificationElement(attributeDataStream, readerState)); } else @@ -297,4 +251,4 @@ public StackMapTableAttribute Parse(Stream attributeDataStream, uint attributeDa return attribute; } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/SyntheticAttribute.cs b/JavaAsm/CustomAttributes/SyntheticAttribute.cs index 6a91057..4e922bf 100644 --- a/JavaAsm/CustomAttributes/SyntheticAttribute.cs +++ b/JavaAsm/CustomAttributes/SyntheticAttribute.cs @@ -1,15 +1,12 @@ using System.IO; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes -{ - public class SyntheticAttribute : CustomAttribute - { +namespace JavaAsm.CustomAttributes { + public class SyntheticAttribute : CustomAttribute { internal override byte[] Save(ClassWriterState writerState, AttributeScope scope) => new byte[0]; } - internal class SyntheticAttributeFactory : ICustomAttributeFactory - { + internal class SyntheticAttributeFactory : ICustomAttributeFactory { public SyntheticAttribute Parse(Stream attributeDataStream, uint attributeDataLength, ClassReaderState readerState, AttributeScope scope) => new SyntheticAttribute(); } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/TypeAnnotation/CatchTarget.cs b/JavaAsm/CustomAttributes/TypeAnnotation/CatchTarget.cs index 352b598..b4102ac 100644 --- a/JavaAsm/CustomAttributes/TypeAnnotation/CatchTarget.cs +++ b/JavaAsm/CustomAttributes/TypeAnnotation/CatchTarget.cs @@ -2,22 +2,18 @@ using BinaryEncoding; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes.TypeAnnotation -{ - public class CatchTarget : TypeAnnotationTarget - { +namespace JavaAsm.CustomAttributes.TypeAnnotation { + public class CatchTarget : TypeAnnotationTarget { public ushort ExceptionTableIndex { get; set; } public override TargetTypeKind TargetTypeKind => TargetTypeKind.Catch; - internal override void Write(Stream stream, ClassWriterState writerState) - { - Binary.BigEndian.Write(stream, ExceptionTableIndex); + internal override void Write(Stream stream, ClassWriterState writerState) { + Binary.BigEndian.Write(stream, this.ExceptionTableIndex); } - internal override void Read(Stream stream, ClassReaderState readerState) - { - ExceptionTableIndex = Binary.BigEndian.ReadUInt16(stream); + internal override void Read(Stream stream, ClassReaderState readerState) { + this.ExceptionTableIndex = Binary.BigEndian.ReadUInt16(stream); } } } \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/TypeAnnotation/EmptyTarget.cs b/JavaAsm/CustomAttributes/TypeAnnotation/EmptyTarget.cs index d6bd0ef..5ac7e63 100644 --- a/JavaAsm/CustomAttributes/TypeAnnotation/EmptyTarget.cs +++ b/JavaAsm/CustomAttributes/TypeAnnotation/EmptyTarget.cs @@ -1,10 +1,8 @@ using System.IO; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes.TypeAnnotation -{ - public class EmptyTarget : TypeAnnotationTarget - { +namespace JavaAsm.CustomAttributes.TypeAnnotation { + public class EmptyTarget : TypeAnnotationTarget { public override TargetTypeKind TargetTypeKind => TargetTypeKind.Empty; internal override void Write(Stream stream, ClassWriterState writerState) { } diff --git a/JavaAsm/CustomAttributes/TypeAnnotation/FormalParameterTarget.cs b/JavaAsm/CustomAttributes/TypeAnnotation/FormalParameterTarget.cs index a697871..d84ddd0 100644 --- a/JavaAsm/CustomAttributes/TypeAnnotation/FormalParameterTarget.cs +++ b/JavaAsm/CustomAttributes/TypeAnnotation/FormalParameterTarget.cs @@ -2,22 +2,18 @@ using JavaAsm.Helpers; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes.TypeAnnotation -{ - public class FormalParameterTarget : TypeAnnotationTarget - { +namespace JavaAsm.CustomAttributes.TypeAnnotation { + public class FormalParameterTarget : TypeAnnotationTarget { public byte FormalParameterIndex { get; set; } public override TargetTypeKind TargetTypeKind => TargetTypeKind.FormalParameter; - internal override void Write(Stream stream, ClassWriterState writerState) - { - stream.WriteByte(FormalParameterIndex); + internal override void Write(Stream stream, ClassWriterState writerState) { + stream.WriteByte(this.FormalParameterIndex); } - internal override void Read(Stream stream, ClassReaderState readerState) - { - FormalParameterIndex = stream.ReadByteFully(); + internal override void Read(Stream stream, ClassReaderState readerState) { + this.FormalParameterIndex = stream.ReadByteFully(); } } } \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/TypeAnnotation/LocalvarTarget.cs b/JavaAsm/CustomAttributes/TypeAnnotation/LocalvarTarget.cs index d6d4eb9..fca7853 100644 --- a/JavaAsm/CustomAttributes/TypeAnnotation/LocalvarTarget.cs +++ b/JavaAsm/CustomAttributes/TypeAnnotation/LocalvarTarget.cs @@ -4,12 +4,9 @@ using BinaryEncoding; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes.TypeAnnotation -{ - public class LocalvarTarget : TypeAnnotationTarget - { - public class TableEntry - { +namespace JavaAsm.CustomAttributes.TypeAnnotation { + public class LocalvarTarget : TypeAnnotationTarget { + public class TableEntry { public ushort StartPc { get; set; } public ushort Length { get; set; } @@ -21,27 +18,22 @@ public class TableEntry public override TargetTypeKind TargetTypeKind => TargetTypeKind.Localvar; - internal override void Write(Stream stream, ClassWriterState writerState) - { - if (Table.Count > ushort.MaxValue) - throw new ArgumentOutOfRangeException(nameof(Table.Count), $"Table is too big: {Table.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(stream, (ushort) Table.Count); - foreach (var entry in Table) - { + internal override void Write(Stream stream, ClassWriterState writerState) { + if (this.Table.Count > ushort.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.Table.Count), $"Table is too big: {this.Table.Count} > {ushort.MaxValue}"); + Binary.BigEndian.Write(stream, (ushort) this.Table.Count); + foreach (TableEntry entry in this.Table) { Binary.BigEndian.Write(stream, entry.StartPc); Binary.BigEndian.Write(stream, entry.Length); Binary.BigEndian.Write(stream, entry.Index); } } - internal override void Read(Stream stream, ClassReaderState readerState) - { - var tableSize = Binary.BigEndian.ReadUInt16(stream); - Table.Capacity = tableSize; - for (var i = 0; i < tableSize; i++) - { - Table.Add(new TableEntry - { + internal override void Read(Stream stream, ClassReaderState readerState) { + ushort tableSize = Binary.BigEndian.ReadUInt16(stream); + this.Table.Capacity = tableSize; + for (int i = 0; i < tableSize; i++) { + this.Table.Add(new TableEntry { StartPc = Binary.BigEndian.ReadUInt16(stream), Length = Binary.BigEndian.ReadUInt16(stream), Index = Binary.BigEndian.ReadUInt16(stream) diff --git a/JavaAsm/CustomAttributes/TypeAnnotation/OffsetTarget.cs b/JavaAsm/CustomAttributes/TypeAnnotation/OffsetTarget.cs index 1c0684b..1535767 100644 --- a/JavaAsm/CustomAttributes/TypeAnnotation/OffsetTarget.cs +++ b/JavaAsm/CustomAttributes/TypeAnnotation/OffsetTarget.cs @@ -2,22 +2,18 @@ using BinaryEncoding; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes.TypeAnnotation -{ - public class OffsetTarget : TypeAnnotationTarget - { +namespace JavaAsm.CustomAttributes.TypeAnnotation { + public class OffsetTarget : TypeAnnotationTarget { public ushort Offset { get; set; } public override TargetTypeKind TargetTypeKind => TargetTypeKind.Offset; - internal override void Write(Stream stream, ClassWriterState writerState) - { - Binary.BigEndian.Write(stream, Offset); + internal override void Write(Stream stream, ClassWriterState writerState) { + Binary.BigEndian.Write(stream, this.Offset); } - internal override void Read(Stream stream, ClassReaderState readerState) - { - Offset = Binary.BigEndian.ReadUInt16(stream); + internal override void Read(Stream stream, ClassReaderState readerState) { + this.Offset = Binary.BigEndian.ReadUInt16(stream); } } } \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/TypeAnnotation/SupertypeTarget.cs b/JavaAsm/CustomAttributes/TypeAnnotation/SupertypeTarget.cs index 42b86ae..77508b4 100644 --- a/JavaAsm/CustomAttributes/TypeAnnotation/SupertypeTarget.cs +++ b/JavaAsm/CustomAttributes/TypeAnnotation/SupertypeTarget.cs @@ -2,22 +2,18 @@ using BinaryEncoding; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes.TypeAnnotation -{ - public class SupertypeTarget : TypeAnnotationTarget - { +namespace JavaAsm.CustomAttributes.TypeAnnotation { + public class SupertypeTarget : TypeAnnotationTarget { public ushort SupertypeIndex { get; set; } public override TargetTypeKind TargetTypeKind => TargetTypeKind.Supertype; - internal override void Write(Stream stream, ClassWriterState writerState) - { - Binary.BigEndian.Write(stream, SupertypeIndex); + internal override void Write(Stream stream, ClassWriterState writerState) { + Binary.BigEndian.Write(stream, this.SupertypeIndex); } - internal override void Read(Stream stream, ClassReaderState readerState) - { - SupertypeIndex = Binary.BigEndian.ReadUInt16(stream); + internal override void Read(Stream stream, ClassReaderState readerState) { + this.SupertypeIndex = Binary.BigEndian.ReadUInt16(stream); } } } \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/TypeAnnotation/TargetType.cs b/JavaAsm/CustomAttributes/TypeAnnotation/TargetType.cs index 4c342a1..7a24808 100644 --- a/JavaAsm/CustomAttributes/TypeAnnotation/TargetType.cs +++ b/JavaAsm/CustomAttributes/TypeAnnotation/TargetType.cs @@ -1,7 +1,5 @@ -namespace JavaAsm.CustomAttributes.TypeAnnotation -{ - public enum TargetType - { +namespace JavaAsm.CustomAttributes.TypeAnnotation { + public enum TargetType { // Type in ... GenericClassOrInterfaceDeclaration = 0x00, @@ -14,7 +12,7 @@ public enum TargetType ReceiverTypeOfMethodOrConstructor = 0x15, TypeInFormalParameterOfMethodOrConstructorOrLambda = 0x16, ThrowsClause = 0x17, - + LocalVariableDeclaration = 0x40, ResourceVariableDeclaration = 0x41, ExceptionParameterDeclaration = 0x42, diff --git a/JavaAsm/CustomAttributes/TypeAnnotation/TargetTypeKind.cs b/JavaAsm/CustomAttributes/TypeAnnotation/TargetTypeKind.cs index 2bdd4d6..4d14fb1 100644 --- a/JavaAsm/CustomAttributes/TypeAnnotation/TargetTypeKind.cs +++ b/JavaAsm/CustomAttributes/TypeAnnotation/TargetTypeKind.cs @@ -1,7 +1,5 @@ -namespace JavaAsm.CustomAttributes.TypeAnnotation -{ - public enum TargetTypeKind - { +namespace JavaAsm.CustomAttributes.TypeAnnotation { + public enum TargetTypeKind { TypeParameter, Supertype, TypeParameterBound, diff --git a/JavaAsm/CustomAttributes/TypeAnnotation/ThrowsTarget.cs b/JavaAsm/CustomAttributes/TypeAnnotation/ThrowsTarget.cs index a27cb42..e7766e7 100644 --- a/JavaAsm/CustomAttributes/TypeAnnotation/ThrowsTarget.cs +++ b/JavaAsm/CustomAttributes/TypeAnnotation/ThrowsTarget.cs @@ -2,22 +2,18 @@ using BinaryEncoding; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes.TypeAnnotation -{ - public class ThrowsTarget : TypeAnnotationTarget - { +namespace JavaAsm.CustomAttributes.TypeAnnotation { + public class ThrowsTarget : TypeAnnotationTarget { public ushort ThrowsTypeIndex { get; set; } public override TargetTypeKind TargetTypeKind => TargetTypeKind.Throws; - internal override void Write(Stream stream, ClassWriterState writerState) - { - Binary.BigEndian.Write(stream, ThrowsTypeIndex); + internal override void Write(Stream stream, ClassWriterState writerState) { + Binary.BigEndian.Write(stream, this.ThrowsTypeIndex); } - internal override void Read(Stream stream, ClassReaderState readerState) - { - ThrowsTypeIndex = Binary.BigEndian.ReadUInt16(stream); + internal override void Read(Stream stream, ClassReaderState readerState) { + this.ThrowsTypeIndex = Binary.BigEndian.ReadUInt16(stream); } } } \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/TypeAnnotation/TypeAnnotationNode.cs b/JavaAsm/CustomAttributes/TypeAnnotation/TypeAnnotationNode.cs index 6e763d9..db39010 100644 --- a/JavaAsm/CustomAttributes/TypeAnnotation/TypeAnnotationNode.cs +++ b/JavaAsm/CustomAttributes/TypeAnnotation/TypeAnnotationNode.cs @@ -7,10 +7,8 @@ using JavaAsm.IO; using JavaAsm.IO.ConstantPoolEntries; -namespace JavaAsm.CustomAttributes.TypeAnnotation -{ - public class TypeAnnotationNode - { +namespace JavaAsm.CustomAttributes.TypeAnnotation { + public class TypeAnnotationNode { public TargetType TargetType { get; set; } public TypeAnnotationTarget Target { get; set; } @@ -19,8 +17,7 @@ public class TypeAnnotationNode public TypeDescriptor Type { get; set; } - public class ElementValuePair - { + public class ElementValuePair { public string ElementName { get; set; } public ElementValue Value { get; set; } @@ -28,98 +25,112 @@ public class ElementValuePair public List ElementValuePairs { get; set; } = new List(); - internal static TypeAnnotationNode Parse(Stream stream, ClassReaderState readerState, AttributeScope scope) - { - var typeAnnotation = new TypeAnnotationNode - { + internal static TypeAnnotationNode Parse(Stream stream, ClassReaderState readerState, AttributeScope scope) { + TypeAnnotationNode typeAnnotation = new TypeAnnotationNode { TargetType = (TargetType) stream.ReadByteFully() }; - typeAnnotation.Target = typeAnnotation.TargetType switch - { - TargetType.GenericClassOrInterfaceDeclaration when scope == AttributeScope.Class => (TypeAnnotationTarget) new TypeParameterTarget(), - TargetType.GenericMethodOrConstructorDeclaration when scope == AttributeScope.Method => new TypeParameterTarget(), - TargetType.ExtendsOrImplements when scope == AttributeScope.Class => new SupertypeTarget(), - TargetType.TypeInBoundInGenericClassOrInterface when scope == AttributeScope.Class => new TypeParameterBoundTarget(), - TargetType.TypeInBoundInGenericMethodOrConstructor when scope == AttributeScope.Method => new TypeParameterBoundTarget(), - TargetType.FieldDeclaration when scope == AttributeScope.Field => new EmptyTarget(), - TargetType.ReturnTypeOrNewObject when scope == AttributeScope.Method => new EmptyTarget(), - TargetType.ReceiverTypeOfMethodOrConstructor when scope == AttributeScope.Method => new EmptyTarget(), - TargetType.TypeInFormalParameterOfMethodOrConstructorOrLambda when scope == AttributeScope.Method => new FormalParameterTarget(), - TargetType.ThrowsClause when scope == AttributeScope.Method => new ThrowsTarget(), - TargetType.LocalVariableDeclaration when scope == AttributeScope.Code => new LocalvarTarget(), - TargetType.ResourceVariableDeclaration when scope == AttributeScope.Code => new LocalvarTarget(), - TargetType.ExceptionParameterDeclaration when scope == AttributeScope.Code => new CatchTarget(), - TargetType.InstanceOfExpression when scope == AttributeScope.Code => new OffsetTarget(), - TargetType.NewExpression when scope == AttributeScope.Code => new OffsetTarget(), - TargetType.MethodReferenceExpressionNew when scope == AttributeScope.Code => new OffsetTarget(), - TargetType.MethodReferenceExpressionIdentifier when scope == AttributeScope.Code => new OffsetTarget(), - TargetType.CastExpression when scope == AttributeScope.Code => new TypeArgumentTarget(), - TargetType.ArgumentForGenericConstructorInvocation when scope == AttributeScope.Code => new TypeArgumentTarget(), - TargetType.ArgumentForGenericMethodInvocation when scope == AttributeScope.Code => new TypeArgumentTarget(), - TargetType.ArgumentForGenericMethodReferenceExpressionNew when scope == AttributeScope.Code => new TypeArgumentTarget(), - TargetType.ArgumentForGenericMethodReferenceExpressionIdentifier when scope == AttributeScope.Code => new TypeArgumentTarget(), - _ => throw new ArgumentOutOfRangeException(nameof(TargetType)) - }; + switch (typeAnnotation.TargetType) { + case TargetType.GenericClassOrInterfaceDeclaration when scope == AttributeScope.Class: + typeAnnotation.Target = new TypeParameterTarget(); + break; + case TargetType.GenericMethodOrConstructorDeclaration when scope == AttributeScope.Method: + typeAnnotation.Target = new TypeParameterTarget(); + break; + case TargetType.ExtendsOrImplements when scope == AttributeScope.Class: + typeAnnotation.Target = new SupertypeTarget(); + break; + case TargetType.TypeInBoundInGenericClassOrInterface when scope == AttributeScope.Class: + case TargetType.TypeInBoundInGenericMethodOrConstructor when scope == AttributeScope.Method: + typeAnnotation.Target = new TypeParameterBoundTarget(); + break; + case TargetType.FieldDeclaration when scope == AttributeScope.Field: + case TargetType.ReturnTypeOrNewObject when scope == AttributeScope.Method: + case TargetType.ReceiverTypeOfMethodOrConstructor when scope == AttributeScope.Method: + typeAnnotation.Target = new EmptyTarget(); + break; + case TargetType.TypeInFormalParameterOfMethodOrConstructorOrLambda when scope == AttributeScope.Method: + typeAnnotation.Target = new FormalParameterTarget(); + break; + case TargetType.ThrowsClause when scope == AttributeScope.Method: + typeAnnotation.Target = new ThrowsTarget(); + break; + case TargetType.LocalVariableDeclaration when scope == AttributeScope.Code: + case TargetType.ResourceVariableDeclaration when scope == AttributeScope.Code: + typeAnnotation.Target = new LocalvarTarget(); + break; + case TargetType.ExceptionParameterDeclaration when scope == AttributeScope.Code: + typeAnnotation.Target = new CatchTarget(); + break; + case TargetType.InstanceOfExpression when scope == AttributeScope.Code: + case TargetType.NewExpression when scope == AttributeScope.Code: + case TargetType.MethodReferenceExpressionNew when scope == AttributeScope.Code: + case TargetType.MethodReferenceExpressionIdentifier when scope == AttributeScope.Code: + typeAnnotation.Target = new OffsetTarget(); + break; + case TargetType.CastExpression when scope == AttributeScope.Code: + case TargetType.ArgumentForGenericConstructorInvocation when scope == AttributeScope.Code: + case TargetType.ArgumentForGenericMethodInvocation when scope == AttributeScope.Code: + case TargetType.ArgumentForGenericMethodReferenceExpressionNew when scope == AttributeScope.Code: + case TargetType.ArgumentForGenericMethodReferenceExpressionIdentifier when scope == AttributeScope.Code: + typeAnnotation.Target = new TypeArgumentTarget(); + break; + default: throw new ArgumentOutOfRangeException(nameof(TargetType)); + } + typeAnnotation.Target.Read(stream, readerState); typeAnnotation.TypePath = new TypePath(); typeAnnotation.TypePath.Read(stream, readerState); - var elementValuePairsCount = Binary.BigEndian.ReadUInt16(stream); + ushort elementValuePairsCount = Binary.BigEndian.ReadUInt16(stream); typeAnnotation.ElementValuePairs.Capacity = elementValuePairsCount; - for (var i = 0; i < elementValuePairsCount; i++) - typeAnnotation.ElementValuePairs.Add(new ElementValuePair - { - ElementName = readerState.ConstantPool - .GetEntry(Binary.BigEndian.ReadUInt16(stream)).String, + for (int i = 0; i < elementValuePairsCount; i++) + typeAnnotation.ElementValuePairs.Add(new ElementValuePair { + ElementName = readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(stream)).String, Value = ElementValue.Parse(stream, readerState) }); return typeAnnotation; } - internal void Write(Stream stream, ClassWriterState writerState, AttributeScope scope) - { - stream.WriteByte((byte) TargetType); - switch (TargetType) - { - case TargetType.GenericClassOrInterfaceDeclaration when Target.TargetTypeKind == TargetTypeKind.TypeParameter && scope == AttributeScope.Class: - case TargetType.GenericMethodOrConstructorDeclaration when Target.TargetTypeKind == TargetTypeKind.TypeParameter && scope == AttributeScope.Method: - case TargetType.ExtendsOrImplements when Target.TargetTypeKind == TargetTypeKind.Supertype && scope == AttributeScope.Class: - case TargetType.TypeInBoundInGenericClassOrInterface when Target.TargetTypeKind == TargetTypeKind.TypeParameterBound && scope == AttributeScope.Class: - case TargetType.TypeInBoundInGenericMethodOrConstructor when Target.TargetTypeKind == TargetTypeKind.TypeParameterBound && scope == AttributeScope.Method: - case TargetType.FieldDeclaration when Target.TargetTypeKind == TargetTypeKind.Empty && scope == AttributeScope.Field: - case TargetType.ReturnTypeOrNewObject when Target.TargetTypeKind == TargetTypeKind.Empty && scope == AttributeScope.Method: - case TargetType.ReceiverTypeOfMethodOrConstructor when Target.TargetTypeKind == TargetTypeKind.Empty && scope == AttributeScope.Method: - case TargetType.TypeInFormalParameterOfMethodOrConstructorOrLambda when Target.TargetTypeKind == TargetTypeKind.FormalParameter && scope == AttributeScope.Method: - case TargetType.ThrowsClause when Target.TargetTypeKind == TargetTypeKind.Throws && scope == AttributeScope.Method: - case TargetType.LocalVariableDeclaration when Target.TargetTypeKind == TargetTypeKind.Localvar && scope == AttributeScope.Code: - case TargetType.ResourceVariableDeclaration when Target.TargetTypeKind == TargetTypeKind.Localvar && scope == AttributeScope.Code: - case TargetType.ExceptionParameterDeclaration when Target.TargetTypeKind == TargetTypeKind.Catch && scope == AttributeScope.Code: - case TargetType.InstanceOfExpression when Target.TargetTypeKind == TargetTypeKind.Offset && scope == AttributeScope.Code: - case TargetType.NewExpression when Target.TargetTypeKind == TargetTypeKind.Offset && scope == AttributeScope.Code: - case TargetType.MethodReferenceExpressionNew when Target.TargetTypeKind == TargetTypeKind.Offset && scope == AttributeScope.Code: - case TargetType.MethodReferenceExpressionIdentifier when Target.TargetTypeKind == TargetTypeKind.Offset && scope == AttributeScope.Code: - case TargetType.CastExpression when Target.TargetTypeKind == TargetTypeKind.TypeArgument && scope == AttributeScope.Code: - case TargetType.ArgumentForGenericConstructorInvocation when Target.TargetTypeKind == TargetTypeKind.TypeArgument && scope == AttributeScope.Code: - case TargetType.ArgumentForGenericMethodInvocation when Target.TargetTypeKind == TargetTypeKind.TypeArgument && scope == AttributeScope.Code: - case TargetType.ArgumentForGenericMethodReferenceExpressionNew when Target.TargetTypeKind == TargetTypeKind.TypeArgument && scope == AttributeScope.Code: - case TargetType.ArgumentForGenericMethodReferenceExpressionIdentifier when Target.TargetTypeKind == TargetTypeKind.TypeArgument && scope == AttributeScope.Code: - Target.Write(stream, writerState); + internal void Write(Stream stream, ClassWriterState writerState, AttributeScope scope) { + stream.WriteByte((byte) this.TargetType); + switch (this.TargetType) { + case TargetType.GenericClassOrInterfaceDeclaration when this.Target.TargetTypeKind == TargetTypeKind.TypeParameter && scope == AttributeScope.Class: + case TargetType.GenericMethodOrConstructorDeclaration when this.Target.TargetTypeKind == TargetTypeKind.TypeParameter && scope == AttributeScope.Method: + case TargetType.ExtendsOrImplements when this.Target.TargetTypeKind == TargetTypeKind.Supertype && scope == AttributeScope.Class: + case TargetType.TypeInBoundInGenericClassOrInterface when this.Target.TargetTypeKind == TargetTypeKind.TypeParameterBound && scope == AttributeScope.Class: + case TargetType.TypeInBoundInGenericMethodOrConstructor when this.Target.TargetTypeKind == TargetTypeKind.TypeParameterBound && scope == AttributeScope.Method: + case TargetType.FieldDeclaration when this.Target.TargetTypeKind == TargetTypeKind.Empty && scope == AttributeScope.Field: + case TargetType.ReturnTypeOrNewObject when this.Target.TargetTypeKind == TargetTypeKind.Empty && scope == AttributeScope.Method: + case TargetType.ReceiverTypeOfMethodOrConstructor when this.Target.TargetTypeKind == TargetTypeKind.Empty && scope == AttributeScope.Method: + case TargetType.TypeInFormalParameterOfMethodOrConstructorOrLambda when this.Target.TargetTypeKind == TargetTypeKind.FormalParameter && scope == AttributeScope.Method: + case TargetType.ThrowsClause when this.Target.TargetTypeKind == TargetTypeKind.Throws && scope == AttributeScope.Method: + case TargetType.LocalVariableDeclaration when this.Target.TargetTypeKind == TargetTypeKind.Localvar && scope == AttributeScope.Code: + case TargetType.ResourceVariableDeclaration when this.Target.TargetTypeKind == TargetTypeKind.Localvar && scope == AttributeScope.Code: + case TargetType.ExceptionParameterDeclaration when this.Target.TargetTypeKind == TargetTypeKind.Catch && scope == AttributeScope.Code: + case TargetType.InstanceOfExpression when this.Target.TargetTypeKind == TargetTypeKind.Offset && scope == AttributeScope.Code: + case TargetType.NewExpression when this.Target.TargetTypeKind == TargetTypeKind.Offset && scope == AttributeScope.Code: + case TargetType.MethodReferenceExpressionNew when this.Target.TargetTypeKind == TargetTypeKind.Offset && scope == AttributeScope.Code: + case TargetType.MethodReferenceExpressionIdentifier when this.Target.TargetTypeKind == TargetTypeKind.Offset && scope == AttributeScope.Code: + case TargetType.CastExpression when this.Target.TargetTypeKind == TargetTypeKind.TypeArgument && scope == AttributeScope.Code: + case TargetType.ArgumentForGenericConstructorInvocation when this.Target.TargetTypeKind == TargetTypeKind.TypeArgument && scope == AttributeScope.Code: + case TargetType.ArgumentForGenericMethodInvocation when this.Target.TargetTypeKind == TargetTypeKind.TypeArgument && scope == AttributeScope.Code: + case TargetType.ArgumentForGenericMethodReferenceExpressionNew when this.Target.TargetTypeKind == TargetTypeKind.TypeArgument && scope == AttributeScope.Code: + case TargetType.ArgumentForGenericMethodReferenceExpressionIdentifier when this.Target.TargetTypeKind == TargetTypeKind.TypeArgument && scope == AttributeScope.Code: + this.Target.Write(stream, writerState); break; - default: - throw new ArgumentOutOfRangeException(nameof(TargetType)); + default: throw new ArgumentOutOfRangeException(nameof(this.TargetType)); } - TypePath.Write(stream, writerState); + this.TypePath.Write(stream, writerState); - if (ElementValuePairs.Count > ushort.MaxValue) - throw new ArgumentOutOfRangeException(nameof(ElementValuePairs.Count), - $"Too many ElementValues: {ElementValuePairs.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(stream, (ushort)ElementValuePairs.Count); - foreach (var elementValuePair in ElementValuePairs) - { + if (this.ElementValuePairs.Count > ushort.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.ElementValuePairs.Count), + $"Too many ElementValues: {this.ElementValuePairs.Count} > {ushort.MaxValue}"); + Binary.BigEndian.Write(stream, (ushort) this.ElementValuePairs.Count); + foreach (ElementValuePair elementValuePair in this.ElementValuePairs) { Binary.BigEndian.Write(stream, writerState.ConstantPool.Find(new Utf8Entry(elementValuePair.ElementName))); elementValuePair.Value.Write(stream, writerState); } } } -} +} \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/TypeAnnotation/TypeAnnotationTarget.cs b/JavaAsm/CustomAttributes/TypeAnnotation/TypeAnnotationTarget.cs index d901089..53eaeac 100644 --- a/JavaAsm/CustomAttributes/TypeAnnotation/TypeAnnotationTarget.cs +++ b/JavaAsm/CustomAttributes/TypeAnnotation/TypeAnnotationTarget.cs @@ -1,10 +1,8 @@ using System.IO; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes.TypeAnnotation -{ - public abstract class TypeAnnotationTarget - { +namespace JavaAsm.CustomAttributes.TypeAnnotation { + public abstract class TypeAnnotationTarget { public abstract TargetTypeKind TargetTypeKind { get; } internal abstract void Write(Stream stream, ClassWriterState writerState); diff --git a/JavaAsm/CustomAttributes/TypeAnnotation/TypeArgumentTarget.cs b/JavaAsm/CustomAttributes/TypeAnnotation/TypeArgumentTarget.cs index 608ca01..f729308 100644 --- a/JavaAsm/CustomAttributes/TypeAnnotation/TypeArgumentTarget.cs +++ b/JavaAsm/CustomAttributes/TypeAnnotation/TypeArgumentTarget.cs @@ -3,26 +3,22 @@ using JavaAsm.Helpers; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes.TypeAnnotation -{ - public class TypeArgumentTarget : TypeAnnotationTarget - { +namespace JavaAsm.CustomAttributes.TypeAnnotation { + public class TypeArgumentTarget : TypeAnnotationTarget { public ushort Offset { get; set; } public byte TypeArgumentIndex { get; set; } public override TargetTypeKind TargetTypeKind => TargetTypeKind.TypeArgument; - internal override void Write(Stream stream, ClassWriterState writerState) - { - Binary.BigEndian.Write(stream, Offset); - stream.WriteByte(TypeArgumentIndex); + internal override void Write(Stream stream, ClassWriterState writerState) { + Binary.BigEndian.Write(stream, this.Offset); + stream.WriteByte(this.TypeArgumentIndex); } - internal override void Read(Stream stream, ClassReaderState readerState) - { - Offset = Binary.BigEndian.ReadUInt16(stream); - TypeArgumentIndex = stream.ReadByteFully(); + internal override void Read(Stream stream, ClassReaderState readerState) { + this.Offset = Binary.BigEndian.ReadUInt16(stream); + this.TypeArgumentIndex = stream.ReadByteFully(); } } } \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/TypeAnnotation/TypeParameterBoundTarget.cs b/JavaAsm/CustomAttributes/TypeAnnotation/TypeParameterBoundTarget.cs index 8c1d8ce..196a16c 100644 --- a/JavaAsm/CustomAttributes/TypeAnnotation/TypeParameterBoundTarget.cs +++ b/JavaAsm/CustomAttributes/TypeAnnotation/TypeParameterBoundTarget.cs @@ -2,26 +2,22 @@ using JavaAsm.Helpers; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes.TypeAnnotation -{ - public class TypeParameterBoundTarget : TypeAnnotationTarget - { +namespace JavaAsm.CustomAttributes.TypeAnnotation { + public class TypeParameterBoundTarget : TypeAnnotationTarget { public byte TypeParameterIndex { get; set; } public byte BoundIndex { get; set; } public override TargetTypeKind TargetTypeKind => TargetTypeKind.TypeParameterBound; - internal override void Write(Stream stream, ClassWriterState writerState) - { - stream.WriteByte(TypeParameterIndex); - stream.WriteByte(BoundIndex); + internal override void Write(Stream stream, ClassWriterState writerState) { + stream.WriteByte(this.TypeParameterIndex); + stream.WriteByte(this.BoundIndex); } - internal override void Read(Stream stream, ClassReaderState readerState) - { - TypeParameterIndex = stream.ReadByteFully(); - BoundIndex = stream.ReadByteFully(); + internal override void Read(Stream stream, ClassReaderState readerState) { + this.TypeParameterIndex = stream.ReadByteFully(); + this.BoundIndex = stream.ReadByteFully(); } } } \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/TypeAnnotation/TypeParameterTarget.cs b/JavaAsm/CustomAttributes/TypeAnnotation/TypeParameterTarget.cs index d964ed3..b384f25 100644 --- a/JavaAsm/CustomAttributes/TypeAnnotation/TypeParameterTarget.cs +++ b/JavaAsm/CustomAttributes/TypeAnnotation/TypeParameterTarget.cs @@ -2,22 +2,18 @@ using JavaAsm.Helpers; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes.TypeAnnotation -{ - public class TypeParameterTarget : TypeAnnotationTarget - { +namespace JavaAsm.CustomAttributes.TypeAnnotation { + public class TypeParameterTarget : TypeAnnotationTarget { public byte TypeParameterIndex { get; set; } public override TargetTypeKind TargetTypeKind => TargetTypeKind.TypeParameter; - internal override void Write(Stream stream, ClassWriterState writerState) - { - stream.WriteByte(TypeParameterIndex); + internal override void Write(Stream stream, ClassWriterState writerState) { + stream.WriteByte(this.TypeParameterIndex); } - internal override void Read(Stream stream, ClassReaderState readerState) - { - TypeParameterIndex = stream.ReadByteFully(); + internal override void Read(Stream stream, ClassReaderState readerState) { + this.TypeParameterIndex = stream.ReadByteFully(); } } } \ No newline at end of file diff --git a/JavaAsm/CustomAttributes/TypeAnnotation/TypePath.cs b/JavaAsm/CustomAttributes/TypeAnnotation/TypePath.cs index cb275de..4c2904a 100644 --- a/JavaAsm/CustomAttributes/TypeAnnotation/TypePath.cs +++ b/JavaAsm/CustomAttributes/TypeAnnotation/TypePath.cs @@ -4,20 +4,16 @@ using JavaAsm.Helpers; using JavaAsm.IO; -namespace JavaAsm.CustomAttributes.TypeAnnotation -{ - public class TypePath - { - public enum TypePathKind - { +namespace JavaAsm.CustomAttributes.TypeAnnotation { + public class TypePath { + public enum TypePathKind { DeeperInArray, DeeperInNested, Wildcard, Type } - public class PathPart - { + public class PathPart { public TypePathKind TypePathKind { get; set; } public byte TypeArgumentIndex { get; set; } @@ -25,27 +21,22 @@ public class PathPart public List Path { get; set; } = new List(); - internal void Read(Stream stream, ClassReaderState classReaderState) - { - var pathSize = stream.ReadByteFully(); - Path.Capacity = pathSize; - for (var i = 0; i < pathSize; i++) - { - Path.Add(new PathPart - { + internal void Read(Stream stream, ClassReaderState classReaderState) { + byte pathSize = stream.ReadByteFully(); + this.Path.Capacity = pathSize; + for (int i = 0; i < pathSize; i++) { + this.Path.Add(new PathPart { TypePathKind = (TypePathKind) stream.ReadByteFully(), TypeArgumentIndex = stream.ReadByteFully() }); } } - internal void Write(Stream stream, ClassWriterState writerState) - { - if (Path.Count > byte.MaxValue) - throw new ArgumentOutOfRangeException(nameof(Path.Count), $"Path is too big: {Path.Count} > {byte.MaxValue}"); - stream.WriteByte((byte) Path.Count); - foreach (var part in Path) - { + internal void Write(Stream stream, ClassWriterState writerState) { + if (this.Path.Count > byte.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.Path.Count), $"Path is too big: {this.Path.Count} > {byte.MaxValue}"); + stream.WriteByte((byte) this.Path.Count); + foreach (PathPart part in this.Path) { stream.WriteByte((byte) part.TypePathKind); stream.WriteByte(part.TypeArgumentIndex); } diff --git a/JavaAsm/FieldNode.cs b/JavaAsm/FieldNode.cs index b8b1303..d95670f 100644 --- a/JavaAsm/FieldNode.cs +++ b/JavaAsm/FieldNode.cs @@ -5,13 +5,11 @@ using JavaAsm.CustomAttributes.Annotation; using JavaAsm.IO; -namespace JavaAsm -{ +namespace JavaAsm { /// /// Field node /// - public class FieldNode - { + public class FieldNode { /// /// Owner class /// @@ -63,117 +61,95 @@ public class FieldNode /// Constant value /// public object ConstantValue { get; set; } - + /// /// Returns and deletes attribute. Used for internal methods to parse contents /// /// Name of annotation /// null, if attribute does not exist or AttributeNode if exists - private AttributeNode GetAttribute(string name) - { - var attribute = Attributes.FirstOrDefault(a => a.Name == name); + private AttributeNode GetAttribute(string name) { + AttributeNode attribute = this.Attributes.FirstOrDefault(a => a.Name == name); if (attribute != null) - Attributes.Remove(attribute); + this.Attributes.Remove(attribute); return attribute; } - + /// /// Parses field annotations to fill up information /// /// Class reader state - internal void Parse(ClassReaderState readerState) - { - Signature = (GetAttribute(PredefinedAttributeNames.Signature)?.ParsedAttribute as SignatureAttribute)?.Value; + internal void Parse(ClassReaderState readerState) { + this.Signature = (GetAttribute(PredefinedAttributeNames.Signature)?.ParsedAttribute as SignatureAttribute)?.Value; { - var attribute = GetAttribute(PredefinedAttributeNames.RuntimeInvisibleAnnotations); + AttributeNode attribute = GetAttribute(PredefinedAttributeNames.RuntimeInvisibleAnnotations); if (attribute != null) - InvisibleAnnotations = (attribute.ParsedAttribute as RuntimeInvisibleAnnotationsAttribute)?.Annotations; + this.InvisibleAnnotations = (attribute.ParsedAttribute as RuntimeInvisibleAnnotationsAttribute)?.Annotations; } { - var attribute = GetAttribute(PredefinedAttributeNames.RuntimeVisibleAnnotations); + AttributeNode attribute = GetAttribute(PredefinedAttributeNames.RuntimeVisibleAnnotations); if (attribute != null) - VisibleAnnotations = (attribute.ParsedAttribute as RuntimeVisibleAnnotationsAttribute)?.Annotations; + this.VisibleAnnotations = (attribute.ParsedAttribute as RuntimeVisibleAnnotationsAttribute)?.Annotations; } - ConstantValue = + this.ConstantValue = (GetAttribute(PredefinedAttributeNames.ConstantValue)?.ParsedAttribute as ConstantValueAttribute)?.Value; - IsDeprecated = GetAttribute(PredefinedAttributeNames.Deprecated)?.ParsedAttribute != null; + this.IsDeprecated = GetAttribute(PredefinedAttributeNames.Deprecated)?.ParsedAttribute != null; } /// /// Saves method information to annotations /// /// Class writer state - internal void Save(ClassWriterState writerState) - { - if (Signature != null) - { - if (Attributes.Any(x => x.Name == PredefinedAttributeNames.Signature)) - throw new Exception( - $"{PredefinedAttributeNames.Signature} attribute is already presented on field"); - Attributes.Add(new AttributeNode - { + internal void Save(ClassWriterState writerState) { + if (this.Signature != null) { + if (this.Attributes.Any(x => x.Name == PredefinedAttributeNames.Signature)) + throw new Exception($"{PredefinedAttributeNames.Signature} attribute is already presented on field"); + this.Attributes.Add(new AttributeNode { Name = PredefinedAttributeNames.Signature, - ParsedAttribute = new SignatureAttribute - { - Value = Signature + ParsedAttribute = new SignatureAttribute { + Value = this.Signature } }); } - if (InvisibleAnnotations != null && InvisibleAnnotations.Count > 0) - { - if (Attributes.Any(x => x.Name == PredefinedAttributeNames.RuntimeInvisibleAnnotations)) - throw new Exception( - $"{PredefinedAttributeNames.RuntimeInvisibleAnnotations} attribute is already presented on field"); - Attributes.Add(new AttributeNode - { + if (this.InvisibleAnnotations != null && this.InvisibleAnnotations.Count > 0) { + if (this.Attributes.Any(x => x.Name == PredefinedAttributeNames.RuntimeInvisibleAnnotations)) + throw new Exception($"{PredefinedAttributeNames.RuntimeInvisibleAnnotations} attribute is already presented on field"); + this.Attributes.Add(new AttributeNode { Name = PredefinedAttributeNames.RuntimeInvisibleAnnotations, - ParsedAttribute = new RuntimeInvisibleAnnotationsAttribute - { - Annotations = InvisibleAnnotations + ParsedAttribute = new RuntimeInvisibleAnnotationsAttribute { + Annotations = this.InvisibleAnnotations } }); } - if (VisibleAnnotations != null && VisibleAnnotations.Count > 0) - { - if (Attributes.Any(x => x.Name == PredefinedAttributeNames.RuntimeVisibleAnnotations)) - throw new Exception( - $"{PredefinedAttributeNames.RuntimeVisibleAnnotations} attribute is already presented on field"); - Attributes.Add(new AttributeNode - { + if (this.VisibleAnnotations != null && this.VisibleAnnotations.Count > 0) { + if (this.Attributes.Any(x => x.Name == PredefinedAttributeNames.RuntimeVisibleAnnotations)) + throw new Exception($"{PredefinedAttributeNames.RuntimeVisibleAnnotations} attribute is already presented on field"); + this.Attributes.Add(new AttributeNode { Name = PredefinedAttributeNames.RuntimeVisibleAnnotations, - ParsedAttribute = new RuntimeVisibleAnnotationsAttribute - { - Annotations = VisibleAnnotations + ParsedAttribute = new RuntimeVisibleAnnotationsAttribute { + Annotations = this.VisibleAnnotations } }); } - if (ConstantValue != null) - { - if (Attributes.Any(x => x.Name == PredefinedAttributeNames.ConstantValue)) - throw new Exception( - $"{PredefinedAttributeNames.ConstantValue} attribute is already presented on field"); - Attributes.Add(new AttributeNode - { + if (this.ConstantValue != null) { + if (this.Attributes.Any(x => x.Name == PredefinedAttributeNames.ConstantValue)) + throw new Exception($"{PredefinedAttributeNames.ConstantValue} attribute is already presented on field"); + this.Attributes.Add(new AttributeNode { Name = PredefinedAttributeNames.ConstantValue, - ParsedAttribute = new ConstantValueAttribute - { - Value = ConstantValue + ParsedAttribute = new ConstantValueAttribute { + Value = this.ConstantValue } }); } // ReSharper disable once InvertIf - if (IsDeprecated) - { - if (Attributes.Any(x => x.Name == PredefinedAttributeNames.Deprecated)) - throw new Exception( - $"{PredefinedAttributeNames.Deprecated} attribute is already presented on field"); - Attributes.Add(new AttributeNode - { + if (this.IsDeprecated) { + if (this.Attributes.Any(x => x.Name == PredefinedAttributeNames.Deprecated)) + throw new Exception($"{PredefinedAttributeNames.Deprecated} attribute is already presented on field"); + this.Attributes.Add(new AttributeNode { Name = PredefinedAttributeNames.Deprecated, ParsedAttribute = new DeprecatedAttribute() }); @@ -181,9 +157,8 @@ internal void Save(ClassWriterState writerState) } /// - public override string ToString() - { - return $"{AccessModifiersExtensions.ToString(Access)} {Descriptor} {Name}"; + public override string ToString() { + return $"{AccessModifiersExtensions.ToString(this.Access)} {this.Descriptor} {this.Name}"; } } } \ No newline at end of file diff --git a/JavaAsm/Helpers/Extensions.cs b/JavaAsm/Helpers/Extensions.cs index 1c02c8f..b9c2606 100644 --- a/JavaAsm/Helpers/Extensions.cs +++ b/JavaAsm/Helpers/Extensions.cs @@ -1,59 +1,115 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using JavaAsm.Instructions.Types; -namespace JavaAsm.Helpers -{ - internal static class Extensions - { - public static bool In(this T value, params T[] values) - { +namespace JavaAsm.Helpers { + internal static class CollectionUtils { + // A small performance helper, because the one used before converted T[] to IEnumerable + public static bool Contains(this T[] array, in T value) { + return Contains(array, value, EqualityComparer.Default); + } + + public static bool Contains(this T[] array, in T value, EqualityComparer comparer) { + for (int i = 0; i < array.Length; i++) { + if (comparer.Equals(array[i], value)) { + return true; + } + } + + return false; + } + + public static bool TryGetAt(IList list, int index, out T value) { + if (index < 0 || index >= list.Count) { + value = default; + return false; + } + else { + value = list[index]; + return true; + } + } + + public static bool TryGetAtNonNull(IList list, int index, out T value) where T : class { + if (index < 0 || index >= list.Count) { + value = default; + return false; + } + else { + value = list[index]; + return value != null; + } + } + } + + internal static class Extensions { + public static char[] Repeat(this char character, int count) { + char[] array = new char[count]; + for (int i = 0; i < count; ++i) + array[i] = character; + return array; + } + + public static bool In(this T value, params T[] values) { return values.Contains(value); } - public static void CheckInAndThrow(this T value, string valueName, params T[] values) - { + public static void CheckInAndThrow(this T value, string valueName, params T[] values) { + if (!values.Contains(value)) + throw new ArgumentOutOfRangeException(nameof(valueName), $"{valueName} is not in [{string.Join(", ", values)}]"); + } + + public static T VerifyOpcode(this T value, string valueName, params T[] values) { if (!values.Contains(value)) throw new ArgumentOutOfRangeException(nameof(valueName), $"{valueName} is not in [{string.Join(", ", values)}]"); + return value; } - public static bool TryAdd(this ICollection collection, T value) - { + public static bool TryAdd(this ICollection collection, T value) { if (collection.Contains(value)) return false; collection.Add(value); return true; } + + public static bool TryAdd(this IDictionary collection, K key, V value) { + if (collection.ContainsKey(key)) + return false; + collection[key] = value; + return true; + } } - internal static class StreamExtensions - { - public static byte ReadByteFully(this Stream stream) - { + internal static class StreamExtensions { + public static byte ReadByteFully(this Stream stream) { return stream.ReadBytes(1)[0]; } - public static byte[] ReadBytes(this Stream stream, long count) - { - var buffer = new byte[count]; - var position = 0; - while (position < buffer.Length) - { - var result = stream.Read(buffer, position, buffer.Length - position); + public static byte[] ReadBytes(this Stream stream, long count) { + byte[] buffer = new byte[count]; + int position = 0; + while (position < buffer.Length) { + int result = stream.Read(buffer, position, buffer.Length - position); if (result <= 0) throw new EndOfStreamException(); position += result; } + return buffer; } + + public static void Write(this Stream stream, byte[] bytes) { + stream.Write(bytes, 0, bytes.Length); + } + + public static int Read(this Stream stream, byte[] bytes) { + return stream.Read(bytes, 0, bytes.Length); + } } - internal static class ReferenceKindTypeExtensions - { - public static bool IsMethodReference(this ReferenceKindType referenceKindType) - { + internal static class ReferenceKindTypeExtensions { + public static bool IsMethodReference(this ReferenceKindType referenceKindType) { return referenceKindType == ReferenceKindType.InvokeReference || referenceKindType == ReferenceKindType.InvokeSpecial || referenceKindType == ReferenceKindType.InvokeStatic || @@ -61,8 +117,7 @@ public static bool IsMethodReference(this ReferenceKindType referenceKindType) referenceKindType == ReferenceKindType.NewInvokeSpecial; } - public static bool IsFieldReference(this ReferenceKindType referenceKindType) - { + public static bool IsFieldReference(this ReferenceKindType referenceKindType) { return referenceKindType == ReferenceKindType.GetField || referenceKindType == ReferenceKindType.GetStatic || referenceKindType == ReferenceKindType.PutField || @@ -70,13 +125,17 @@ public static bool IsFieldReference(this ReferenceKindType referenceKindType) } } - internal static class DictionaryExtensions - { - public static TValue GetOrAdd(this Dictionary dictionary, TKey key, TValue value) - { + internal static class DictionaryExtensions { + public static TValue GetOrAdd(this Dictionary dictionary, TKey key, TValue value) { if (!dictionary.ContainsKey(key)) dictionary.Add(key, value); return dictionary[key]; } + + public static TValue GetOrAdd(this Dictionary dictionary, TKey key, Func provider) { + if (!dictionary.ContainsKey(key)) + dictionary.Add(key, provider()); + return dictionary[key]; + } } -} +} \ No newline at end of file diff --git a/JavaAsm/Helpers/ModifiedUtf8Helper.cs b/JavaAsm/Helpers/ModifiedUtf8Helper.cs index b2ecb38..3c3782b 100644 --- a/JavaAsm/Helpers/ModifiedUtf8Helper.cs +++ b/JavaAsm/Helpers/ModifiedUtf8Helper.cs @@ -1,37 +1,30 @@ using System; -namespace JavaAsm.Helpers -{ - public static class ModifiedUtf8Helper - { - public static byte[] Encode(string value) - { - var offset = 0; - var buffer = new byte[GetBytesCount(value)]; - foreach (var c in value) - { +namespace JavaAsm.Helpers { + public static class ModifiedUtf8Helper { + public static byte[] Encode(string value) { + int offset = 0; + byte[] buffer = new byte[GetBytesCount(value)]; + foreach (char c in value) { if (c != 0 && c <= 127) - buffer[offset++] = (byte)c; - else if (c <= 2047) - { - buffer[offset++] = (byte)(0xc0 | (0x1f & (c >> 6))); - buffer[offset++] = (byte)(0x80 | (0x3f & c)); + buffer[offset++] = (byte) c; + else if (c <= 2047) { + buffer[offset++] = (byte) (0xc0 | (0x1f & (c >> 6))); + buffer[offset++] = (byte) (0x80 | (0x3f & c)); } - else - { - buffer[offset++] = (byte)(0xe0 | (0x0f & (c >> 12))); - buffer[offset++] = (byte)(0x80 | (0x3f & (c >> 6))); - buffer[offset++] = (byte)(0x80 | (0x3f & c)); + else { + buffer[offset++] = (byte) (0xe0 | (0x0f & (c >> 12))); + buffer[offset++] = (byte) (0x80 | (0x3f & (c >> 6))); + buffer[offset++] = (byte) (0x80 | (0x3f & c)); } } + return buffer; } - public static ushort GetBytesCount(string value) - { - var bytesCount = 0; - foreach (var c in value) - { + public static ushort GetBytesCount(string value) { + int bytesCount = 0; + foreach (char c in value) { if (c != 0 && c <= 127) bytesCount++; else if (c <= 2047) @@ -42,40 +35,36 @@ public static ushort GetBytesCount(string value) if (bytesCount > ushort.MaxValue) throw new FormatException("String more than 65535 UTF bytes long"); } + return (ushort) bytesCount; } - public static string Decode(byte[] data) - { - var length = data.Length; - var result = new char[length]; - var count = 0; - var numberOfChars = 0; - while (count < length) - { + public static string Decode(byte[] data) { + int length = data.Length; + char[] result = new char[length]; + int count = 0; + int numberOfChars = 0; + while (count < length) { if ((result[numberOfChars] = (char) data[count++]) < '\u0080') numberOfChars++; - else - { + else { int a; - if (((a = result[numberOfChars]) & 0xe0) == 0xc0) - { + if (((a = result[numberOfChars]) & 0xe0) == 0xc0) { if (count >= length) throw new FormatException($"Bad second byte at {count}"); int b = data[count++]; if ((b & 0xC0) != 0x80) throw new FormatException($"Bad second byte at {count - 1}"); - result[numberOfChars++] = (char)(((a & 0x1F) << 6) | (b & 0x3F)); + result[numberOfChars++] = (char) (((a & 0x1F) << 6) | (b & 0x3F)); } - else if ((a & 0xf0) == 0xe0) - { + else if ((a & 0xf0) == 0xe0) { if (count + 1 >= length) throw new FormatException($"Bad third byte at {count + 1}"); int b = data[count++]; int c = data[count++]; if ((b & 0xC0) != 0x80 || (c & 0xC0) != 0x80) throw new FormatException($"Bad second or third byte at {count - 2}"); - result[numberOfChars++] = (char)(((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F)); + result[numberOfChars++] = (char) (((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F)); } else throw new FormatException($"Bad byte at {count - 1}"); @@ -85,4 +74,4 @@ public static string Decode(byte[] data) return new string(result, 0, numberOfChars); } } -} +} \ No newline at end of file diff --git a/JavaAsm/Helpers/ReadCountStream.cs b/JavaAsm/Helpers/ReadCountStream.cs index fc3a0aa..1423b95 100644 --- a/JavaAsm/Helpers/ReadCountStream.cs +++ b/JavaAsm/Helpers/ReadCountStream.cs @@ -1,29 +1,24 @@ using System; using System.IO; -namespace JavaAsm.Helpers -{ - public class ReadWriteCountStream : Stream - { +namespace JavaAsm.Helpers { + public class ReadWriteCountStream : Stream { private readonly Stream baseStream; public long ReadBytes { get; private set; } public long WrittenBytes { get; private set; } - public ReadWriteCountStream(Stream baseStream) - { + public ReadWriteCountStream(Stream baseStream) { this.baseStream = baseStream; } - public override void Flush() - { - baseStream.Flush(); + public override void Flush() { + this.baseStream.Flush(); } - public override int Read(byte[] buffer, int offset, int count) - { - var result = baseStream.Read(buffer, offset, count); - ReadBytes += Math.Max(0, result); + public override int Read(byte[] buffer, int offset, int count) { + int result = this.baseStream.Read(buffer, offset, count); + this.ReadBytes += Math.Max(0, result); return result; } @@ -31,24 +26,22 @@ public override int Read(byte[] buffer, int offset, int count) public override void SetLength(long value) => throw new InvalidOperationException(); - public override void Write(byte[] buffer, int offset, int count) - { - baseStream.Write(buffer, offset, count); - WrittenBytes += count; + public override void Write(byte[] buffer, int offset, int count) { + this.baseStream.Write(buffer, offset, count); + this.WrittenBytes += count; } - public override bool CanRead => baseStream.CanRead; + public override bool CanRead => this.baseStream.CanRead; public override bool CanSeek => false; - public override bool CanWrite => baseStream.CanWrite; + public override bool CanWrite => this.baseStream.CanWrite; - public override long Length => baseStream.Length; + public override long Length => this.baseStream.Length; - public override long Position - { - get => baseStream.Position; - set => baseStream.Position = value; + public override long Position { + get => this.baseStream.Position; + set => this.baseStream.Position = value; } } -} +} \ No newline at end of file diff --git a/JavaAsm/IDescriptor.cs b/JavaAsm/IDescriptor.cs index 16c12d7..70b77b2 100644 --- a/JavaAsm/IDescriptor.cs +++ b/JavaAsm/IDescriptor.cs @@ -1,7 +1,8 @@ -namespace JavaAsm -{ +namespace JavaAsm { /// /// Common interface for all descriptors /// - public interface IDescriptor { } + public interface IDescriptor { + IDescriptor Copy(); + } } \ No newline at end of file diff --git a/JavaAsm/IO/ClassFile.cs b/JavaAsm/IO/ClassFile.cs index 4661684..ced1c4b 100644 --- a/JavaAsm/IO/ClassFile.cs +++ b/JavaAsm/IO/ClassFile.cs @@ -3,98 +3,89 @@ using BinaryEncoding; using JavaAsm.IO.ConstantPoolEntries; -namespace JavaAsm.IO -{ - public static class ClassFile - { +namespace JavaAsm.IO { + public static class ClassFile { private const uint Magic = 0xCAFEBABE; - internal static AttributeNode ParseAttribute(Stream stream, ClassReaderState state, AttributeScope scope) - { - var attribute = new AttributeNode - { + internal static AttributeNode ParseAttribute(Stream stream, ClassReaderState state, AttributeScope scope) { + AttributeNode attribute = new AttributeNode { Name = state.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(stream)).String }; attribute.Parse(stream, scope, state); return attribute; } - private static FieldNode ParseField(Stream stream, ClassReaderState state) - { - var fieldNode = new FieldNode - { + private static FieldNode ParseField(Stream stream, ClassReaderState state) { + FieldNode fieldNode = new FieldNode { Owner = state.ClassNode, Access = (FieldAccessModifiers) Binary.BigEndian.ReadUInt16(stream), Name = state.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(stream)).String, Descriptor = TypeDescriptor.Parse(state.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(stream)).String) }; - var attributesCount = Binary.BigEndian.ReadUInt16(stream); + ushort attributesCount = Binary.BigEndian.ReadUInt16(stream); fieldNode.Attributes.Capacity = attributesCount; - for (var i = 0; i < attributesCount; i++) + for (int i = 0; i < attributesCount; i++) fieldNode.Attributes.Add(ParseAttribute(stream, state, AttributeScope.Field)); return fieldNode; } - private static MethodNode ParseMethod(Stream stream, ClassReaderState state) - { - var methodNode = new MethodNode - { + private static MethodNode ParseMethod(Stream stream, ClassReaderState state) { + MethodNode methodNode = new MethodNode { Owner = state.ClassNode, - Access = (MethodAccessModifiers)Binary.BigEndian.ReadUInt16(stream), + Access = (MethodAccessModifiers) Binary.BigEndian.ReadUInt16(stream), Name = state.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(stream)).String, Descriptor = MethodDescriptor.Parse(state.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(stream)).String) }; - var attributesCount = Binary.BigEndian.ReadUInt16(stream); + ushort attributesCount = Binary.BigEndian.ReadUInt16(stream); methodNode.Attributes.Capacity = attributesCount; - for (var i = 0; i < attributesCount; i++) + for (int i = 0; i < attributesCount; i++) methodNode.Attributes.Add(ParseAttribute(stream, state, AttributeScope.Method)); return methodNode; } - public static ClassNode ParseClass(Stream stream) - { - var state = new ClassReaderState(); - var result = new ClassNode(); + public static ClassNode ParseClass(Stream stream) { + ClassReaderState state = new ClassReaderState(); + ClassNode result = new ClassNode(); state.ClassNode = result; if (Binary.BigEndian.ReadUInt32(stream) != Magic) throw new IOException("Wrong magic in class"); - + result.MinorVersion = Binary.BigEndian.ReadUInt16(stream); result.MajorVersion = (ClassVersion) Binary.BigEndian.ReadUInt16(stream); if (result.MajorVersion > ClassVersion.Java8) throw new Exception($"Wrong Java version: {result.MajorVersion}"); - var constantPool = new ConstantPool(); + ConstantPool constantPool = new ConstantPool(); constantPool.Read(stream); state.ConstantPool = constantPool; result.Access = (ClassAccessModifiers) Binary.BigEndian.ReadUInt16(stream); - + result.Name = new ClassName(constantPool.GetEntry(Binary.BigEndian.ReadUInt16(stream)).Name.String); result.SuperName = new ClassName(constantPool.GetEntry(Binary.BigEndian.ReadUInt16(stream)).Name.String); - var interfacesCount = Binary.BigEndian.ReadUInt16(stream); + ushort interfacesCount = Binary.BigEndian.ReadUInt16(stream); result.Interfaces.Capacity = interfacesCount; - for (var i = 0; i < interfacesCount; i++) + for (int i = 0; i < interfacesCount; i++) result.Interfaces.Add(new ClassName(constantPool.GetEntry(Binary.BigEndian.ReadUInt16(stream)).Name.String)); - var fieldsCount = Binary.BigEndian.ReadUInt16(stream); + ushort fieldsCount = Binary.BigEndian.ReadUInt16(stream); result.Fields.Capacity = fieldsCount; - for (var i = 0; i < fieldsCount; i++) + for (int i = 0; i < fieldsCount; i++) result.Fields.Add(ParseField(stream, state)); - var methodsCount = Binary.BigEndian.ReadUInt16(stream); + ushort methodsCount = Binary.BigEndian.ReadUInt16(stream); result.Methods.Capacity = methodsCount; - for (var i = 0; i < methodsCount; i++) + for (int i = 0; i < methodsCount; i++) result.Methods.Add(ParseMethod(stream, state)); - var attributesCount = Binary.BigEndian.ReadUInt16(stream); + ushort attributesCount = Binary.BigEndian.ReadUInt16(stream); result.Attributes.Capacity = attributesCount; - for (var i = 0; i < attributesCount; i++) + for (int i = 0; i < attributesCount; i++) result.Attributes.Add(ParseAttribute(stream, state, AttributeScope.Class)); result.Parse(state); @@ -102,49 +93,44 @@ public static ClassNode ParseClass(Stream stream) return result; } - internal static void WriteAttribute(Stream stream, AttributeNode attribute, ClassWriterState state, AttributeScope scope) - { + internal static void WriteAttribute(Stream stream, AttributeNode attribute, ClassWriterState state, AttributeScope scope) { Binary.BigEndian.Write(stream, state.ConstantPool.Find(new Utf8Entry(attribute.Name))); attribute.Data = attribute.ParsedAttribute?.Save(state, scope) ?? attribute.Data; if (attribute.Data.LongLength > uint.MaxValue) throw new ArgumentOutOfRangeException(nameof(attribute.Data.LongLength), $"Attribute data length too big: {attribute.Data.LongLength} > {uint.MaxValue}"); Binary.BigEndian.Write(stream, (uint) attribute.Data.LongLength); - stream.Write(attribute.Data); + stream.Write(attribute.Data, 0, attribute.Data.Length); } - private static void WriteField(Stream stream, FieldNode fieldNode, ClassWriterState state) - { + private static void WriteField(Stream stream, FieldNode fieldNode, ClassWriterState state) { Binary.BigEndian.Write(stream, (ushort) fieldNode.Access); Binary.BigEndian.Write(stream, state.ConstantPool.Find(new Utf8Entry(fieldNode.Name))); Binary.BigEndian.Write(stream, state.ConstantPool.Find(new Utf8Entry(fieldNode.Descriptor.ToString()))); if (fieldNode.Attributes.Count > ushort.MaxValue) throw new ArgumentOutOfRangeException(nameof(fieldNode.Attributes.Count), $"Too many attributes: {fieldNode.Attributes.Count} > {ushort.MaxValue}"); Binary.BigEndian.Write(stream, (ushort) fieldNode.Attributes.Count); - foreach (var attriute in fieldNode.Attributes) + foreach (AttributeNode attriute in fieldNode.Attributes) WriteAttribute(stream, attriute, state, AttributeScope.Field); } - private static void WriteMethod(Stream stream, MethodNode methodNode, ClassWriterState state) - { - Binary.BigEndian.Write(stream, (ushort)methodNode.Access); + private static void WriteMethod(Stream stream, MethodNode methodNode, ClassWriterState state) { + Binary.BigEndian.Write(stream, (ushort) methodNode.Access); Binary.BigEndian.Write(stream, state.ConstantPool.Find(new Utf8Entry(methodNode.Name))); Binary.BigEndian.Write(stream, state.ConstantPool.Find(new Utf8Entry(methodNode.Descriptor.ToString()))); if (methodNode.Attributes.Count > ushort.MaxValue) throw new ArgumentOutOfRangeException(nameof(methodNode.Attributes.Count), $"Too many attributes: {methodNode.Attributes.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(stream, (ushort)methodNode.Attributes.Count); - foreach (var attriute in methodNode.Attributes) + Binary.BigEndian.Write(stream, (ushort) methodNode.Attributes.Count); + foreach (AttributeNode attriute in methodNode.Attributes) WriteAttribute(stream, attriute, state, AttributeScope.Method); } - public static void WriteClass(Stream stream, ClassNode classNode) - { + public static void WriteClass(Stream stream, ClassNode classNode) { Binary.BigEndian.Write(stream, Magic); Binary.BigEndian.Write(stream, classNode.MinorVersion); Binary.BigEndian.Write(stream, (ushort) classNode.MajorVersion); - var afterConstantPoolDataStream = new MemoryStream(); - var constantPool = new ConstantPool(); - var state = new ClassWriterState - { + MemoryStream afterConstantPoolDataStream = new MemoryStream(); + ConstantPool constantPool = new ConstantPool(); + ClassWriterState state = new ClassWriterState { ClassNode = classNode, ConstantPool = constantPool }; @@ -160,30 +146,31 @@ public static void WriteClass(Stream stream, ClassNode classNode) if (classNode.Interfaces.Count > ushort.MaxValue) throw new ArgumentOutOfRangeException(nameof(classNode.Interfaces.Count), $"Too many interfaces: {classNode.Interfaces.Count} > {ushort.MaxValue}"); Binary.BigEndian.Write(afterConstantPoolDataStream, (ushort) classNode.Interfaces.Count); - foreach (var interfaceClassName in classNode.Interfaces) + foreach (ClassName interfaceClassName in classNode.Interfaces) Binary.BigEndian.Write(afterConstantPoolDataStream, constantPool.Find(new ClassEntry(new Utf8Entry(interfaceClassName.Name)))); if (classNode.Fields.Count > ushort.MaxValue) throw new ArgumentOutOfRangeException(nameof(classNode.Fields.Count), $"Too many fields: {classNode.Fields.Count} > {ushort.MaxValue}"); Binary.BigEndian.Write(afterConstantPoolDataStream, (ushort) classNode.Fields.Count); - foreach (var field in classNode.Fields) + foreach (FieldNode field in classNode.Fields) WriteField(afterConstantPoolDataStream, field, state); if (classNode.Methods.Count > ushort.MaxValue) throw new ArgumentOutOfRangeException(nameof(classNode.Methods.Count), $"Too many methods: {classNode.Methods.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(afterConstantPoolDataStream, (ushort)classNode.Methods.Count); - foreach (var method in classNode.Methods) + Binary.BigEndian.Write(afterConstantPoolDataStream, (ushort) classNode.Methods.Count); + foreach (MethodNode method in classNode.Methods) WriteMethod(afterConstantPoolDataStream, method, state); if (classNode.Attributes.Count > ushort.MaxValue) throw new ArgumentOutOfRangeException(nameof(classNode.Attributes.Count), $"Too many attributes: {classNode.Attributes.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(afterConstantPoolDataStream, (ushort)classNode.Attributes.Count); - foreach (var attriute in classNode.Attributes) + Binary.BigEndian.Write(afterConstantPoolDataStream, (ushort) classNode.Attributes.Count); + foreach (AttributeNode attriute in classNode.Attributes) WriteAttribute(afterConstantPoolDataStream, attriute, state, AttributeScope.Class); constantPool.Write(stream); - stream.Write(afterConstantPoolDataStream.ToArray()); + byte[] data = afterConstantPoolDataStream.ToArray(); + stream.Write(data, 0, data.Length); } } -} +} \ No newline at end of file diff --git a/JavaAsm/IO/ClassReaderState.cs b/JavaAsm/IO/ClassReaderState.cs index 0139ebb..f4d7d8e 100644 --- a/JavaAsm/IO/ClassReaderState.cs +++ b/JavaAsm/IO/ClassReaderState.cs @@ -1,7 +1,5 @@ -namespace JavaAsm.IO -{ - internal class ClassReaderState - { +namespace JavaAsm.IO { + internal class ClassReaderState { public ClassNode ClassNode { get; set; } public ConstantPool ConstantPool { get; set; } diff --git a/JavaAsm/IO/ClassWriterState.cs b/JavaAsm/IO/ClassWriterState.cs index d8c67fb..185016d 100644 --- a/JavaAsm/IO/ClassWriterState.cs +++ b/JavaAsm/IO/ClassWriterState.cs @@ -1,7 +1,5 @@ -namespace JavaAsm.IO -{ - internal class ClassWriterState - { +namespace JavaAsm.IO { + internal class ClassWriterState { public ClassNode ClassNode { get; set; } public ConstantPool ConstantPool { get; set; } diff --git a/JavaAsm/IO/ConstantPool.cs b/JavaAsm/IO/ConstantPool.cs index 378b2c5..e14805f 100644 --- a/JavaAsm/IO/ConstantPool.cs +++ b/JavaAsm/IO/ConstantPool.cs @@ -7,97 +7,114 @@ using JavaAsm.Helpers; using JavaAsm.IO.ConstantPoolEntries; -namespace JavaAsm.IO -{ - internal class ConstantPool - { +namespace JavaAsm.IO { + internal class ConstantPool { private readonly Dictionary constantPoolMap = new Dictionary(); private readonly List entries = new List(); - public ushort Find(Entry entry) - { - if (constantPoolMap.ContainsKey(entry)) - { - return constantPoolMap[entry]; + public ushort Find(Entry entry) { + if (this.constantPoolMap.ContainsKey(entry)) { + return this.constantPoolMap[entry]; } entry.PutToConstantPool(this); - entries.Add(entry); - var newKey = (ushort) entries.Count; + this.entries.Add(entry); + ushort newKey = (ushort) this.entries.Count; if (entry is LongEntry || entry is DoubleEntry) - entries.Add(new LongDoublePlaceholderEntry()); - if (entries.Count > ushort.MaxValue) + this.entries.Add(new LongDoublePlaceholderEntry()); + if (this.entries.Count > ushort.MaxValue) throw new Exception("Too much entries in constant pool"); - constantPoolMap.Add(entry, newKey); + this.constantPoolMap.Add(entry, newKey); return newKey; } - public T GetEntry(ushort id) where T : Entry - { - return (T) entries[id - 1]; + public T GetEntry(ushort id) where T : Entry { + return (T) this.entries[id - 1]; } - public void Read(Stream stream) - { - var size = Binary.BigEndian.ReadUInt16(stream); - for (var i = 0; i < size - 1; i++) - { - var tag = (EntryTag) stream.ReadByteFully(); - var entry = tag switch - { - EntryTag.Class => (Entry) new ClassEntry(stream), - EntryTag.FieldReference => new FieldReferenceEntry(stream), - EntryTag.MethodReference => new MethodReferenceEntry(stream), - EntryTag.InterfaceMethodReference => new InterfaceMethodReferenceEntry(stream), - EntryTag.String => new StringEntry(stream), - EntryTag.Integer => new IntegerEntry(stream), - EntryTag.Float => new FloatEntry(stream), - EntryTag.Long => new LongEntry(stream), - EntryTag.Double => new DoubleEntry(stream), - EntryTag.NameAndType => new NameAndTypeEntry(stream), - EntryTag.Utf8 => new Utf8Entry(stream), - EntryTag.MethodHandle => new MethodHandleEntry(stream), - EntryTag.MethodType => new MethodTypeEntry(stream), - EntryTag.InvokeDynamic => new InvokeDynamicEntry(stream), - _ => throw new ArgumentOutOfRangeException(nameof(tag)) - }; + public void Read(Stream stream) { + ushort size = Binary.BigEndian.ReadUInt16(stream); + for (int i = 0; i < size - 1; i++) { + EntryTag tag = (EntryTag) stream.ReadByteFully(); + Entry entry; + switch (tag) { + case EntryTag.Class: + entry = new ClassEntry(stream); + break; + case EntryTag.FieldReference: + entry = new FieldReferenceEntry(stream); + break; + case EntryTag.MethodReference: + entry = new MethodReferenceEntry(stream); + break; + case EntryTag.InterfaceMethodReference: + entry = new InterfaceMethodReferenceEntry(stream); + break; + case EntryTag.String: + entry = new StringEntry(stream); + break; + case EntryTag.Integer: + entry = new IntegerEntry(stream); + break; + case EntryTag.Float: + entry = new FloatEntry(stream); + break; + case EntryTag.Long: + entry = new LongEntry(stream); + break; + case EntryTag.Double: + entry = new DoubleEntry(stream); + break; + case EntryTag.NameAndType: + entry = new NameAndTypeEntry(stream); + break; + case EntryTag.Utf8: + entry = new Utf8Entry(stream); + break; + case EntryTag.MethodHandle: + entry = new MethodHandleEntry(stream); + break; + case EntryTag.MethodType: + entry = new MethodTypeEntry(stream); + break; + case EntryTag.InvokeDynamic: + entry = new InvokeDynamicEntry(stream); + break; + default: throw new ArgumentOutOfRangeException(nameof(tag)); + } + + Debug.Assert(entry.Tag == tag); - entries.Add(entry); + this.entries.Add(entry); if (!(entry is LongEntry) && !(entry is DoubleEntry)) continue; - entries.Add(new LongDoublePlaceholderEntry()); + this.entries.Add(new LongDoublePlaceholderEntry()); i++; } - foreach (var entry in entries) + foreach (Entry entry in this.entries) entry.ProcessFromConstantPool(this); } - private class LongDoublePlaceholderEntry : Entry - { + private class LongDoublePlaceholderEntry : Entry { public override EntryTag Tag => throw new Exception("You shouldn't access that entry"); - public override void ProcessFromConstantPool(ConstantPool constantPool) - { + public override void ProcessFromConstantPool(ConstantPool constantPool) { } - public override void Write(Stream stream) - { + public override void Write(Stream stream) { } - public override void PutToConstantPool(ConstantPool constantPool) - { + public override void PutToConstantPool(ConstantPool constantPool) { } } - public void Write(Stream stream) - { - if (entries.Count > ushort.MaxValue) - throw new ArgumentOutOfRangeException(nameof(entries.Count), - $"Too many entries: {entries.Count} > {ushort.MaxValue}"); - Binary.BigEndian.Write(stream, (ushort) (entries.Count + 1)); - foreach (var entry in entries.Where(entry => !(entry is LongDoublePlaceholderEntry))) - { + public void Write(Stream stream) { + if (this.entries.Count > ushort.MaxValue) + throw new ArgumentOutOfRangeException(nameof(this.entries.Count), + $"Too many entries: {this.entries.Count} > {ushort.MaxValue}"); + Binary.BigEndian.Write(stream, (ushort) (this.entries.Count + 1)); + foreach (Entry entry in this.entries.Where(entry => !(entry is LongDoublePlaceholderEntry))) { stream.WriteByte((byte) entry.Tag); entry.Write(stream); } diff --git a/JavaAsm/IO/ConstantPoolEntries/ClassEntry.cs b/JavaAsm/IO/ConstantPoolEntries/ClassEntry.cs index cce924f..e725215 100644 --- a/JavaAsm/IO/ConstantPoolEntries/ClassEntry.cs +++ b/JavaAsm/IO/ConstantPoolEntries/ClassEntry.cs @@ -3,56 +3,48 @@ using System.IO; using BinaryEncoding; -namespace JavaAsm.IO.ConstantPoolEntries -{ - internal class ClassEntry : Entry - { +namespace JavaAsm.IO.ConstantPoolEntries { + internal class ClassEntry : Entry { public Utf8Entry Name { get; private set; } private ushort nameIndex; - public ClassEntry(Utf8Entry name) - { - Name = name ?? throw new ArgumentNullException(nameof(name)); + public ClassEntry(Utf8Entry name) { + this.Name = name ?? throw new ArgumentNullException(nameof(name)); } - public ClassEntry(Stream stream) - { - nameIndex = Binary.BigEndian.ReadUInt16(stream); + public ClassEntry(Stream stream) { + this.nameIndex = Binary.BigEndian.ReadUInt16(stream); } public override EntryTag Tag => EntryTag.Class; - public override void ProcessFromConstantPool(ConstantPool constantPool) - { - Name = constantPool.GetEntry(nameIndex); + public override void ProcessFromConstantPool(ConstantPool constantPool) { + this.Name = constantPool.GetEntry(this.nameIndex); } - public override void Write(Stream stream) - { - Binary.BigEndian.Write(stream, nameIndex); + public override void Write(Stream stream) { + Binary.BigEndian.Write(stream, this.nameIndex); } - public override void PutToConstantPool(ConstantPool constantPool) - { - nameIndex = constantPool.Find(Name); + public override void PutToConstantPool(ConstantPool constantPool) { + this.nameIndex = constantPool.Find(this.Name); } - private bool Equals(ClassEntry other) - { - return Name.Equals(other.Name); + private bool Equals(ClassEntry other) { + return this.Name.Equals(other.Name); } - public override bool Equals(object obj) - { - if (obj is null) return false; - if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == GetType() && Equals((ClassEntry)obj); + public override bool Equals(object obj) { + if (obj is null) + return false; + if (ReferenceEquals(this, obj)) + return true; + return obj.GetType() == GetType() && Equals((ClassEntry) obj); } [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] - public override int GetHashCode() - { - return Name.GetHashCode(); + public override int GetHashCode() { + return this.Name.GetHashCode(); } } } \ No newline at end of file diff --git a/JavaAsm/IO/ConstantPoolEntries/DoubleEntry.cs b/JavaAsm/IO/ConstantPoolEntries/DoubleEntry.cs index a655d89..e0d2384 100644 --- a/JavaAsm/IO/ConstantPoolEntries/DoubleEntry.cs +++ b/JavaAsm/IO/ConstantPoolEntries/DoubleEntry.cs @@ -2,48 +2,42 @@ using System.IO; using BinaryEncoding; -namespace JavaAsm.IO.ConstantPoolEntries -{ - internal class DoubleEntry : Entry - { +namespace JavaAsm.IO.ConstantPoolEntries { + internal class DoubleEntry : Entry { public double Value { get; } - public DoubleEntry(double value) - { - Value = value; + public DoubleEntry(double value) { + this.Value = value; } - public DoubleEntry(Stream stream) - { - Value = BitConverter.Int64BitsToDouble(Binary.BigEndian.ReadInt64(stream)); + public DoubleEntry(Stream stream) { + this.Value = BitConverter.Int64BitsToDouble(Binary.BigEndian.ReadInt64(stream)); } public override EntryTag Tag => EntryTag.Double; public override void ProcessFromConstantPool(ConstantPool constantPool) { } - public override void Write(Stream stream) - { - Binary.BigEndian.Write(stream, BitConverter.DoubleToInt64Bits(Value)); + public override void Write(Stream stream) { + Binary.BigEndian.Write(stream, BitConverter.DoubleToInt64Bits(this.Value)); } public override void PutToConstantPool(ConstantPool constantPool) { } - private bool Equals(DoubleEntry other) - { - return Value.Equals(other.Value); + private bool Equals(DoubleEntry other) { + return this.Value.Equals(other.Value); } - public override bool Equals(object obj) - { - if (obj is null) return false; - if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == GetType() && Equals((DoubleEntry)obj); + public override bool Equals(object obj) { + if (obj is null) + return false; + if (ReferenceEquals(this, obj)) + return true; + return obj.GetType() == GetType() && Equals((DoubleEntry) obj); } - public override int GetHashCode() - { - return Value.GetHashCode(); + public override int GetHashCode() { + return this.Value.GetHashCode(); } } } \ No newline at end of file diff --git a/JavaAsm/IO/ConstantPoolEntries/Entry.cs b/JavaAsm/IO/ConstantPoolEntries/Entry.cs index 1bca067..b5e65b5 100644 --- a/JavaAsm/IO/ConstantPoolEntries/Entry.cs +++ b/JavaAsm/IO/ConstantPoolEntries/Entry.cs @@ -1,9 +1,7 @@ using System.IO; -namespace JavaAsm.IO.ConstantPoolEntries -{ - internal abstract class Entry - { +namespace JavaAsm.IO.ConstantPoolEntries { + internal abstract class Entry { public abstract EntryTag Tag { get; } public abstract void ProcessFromConstantPool(ConstantPool constantPool); @@ -12,4 +10,4 @@ internal abstract class Entry public abstract void PutToConstantPool(ConstantPool constantPool); } -} +} \ No newline at end of file diff --git a/JavaAsm/IO/ConstantPoolEntries/EntryTag.cs b/JavaAsm/IO/ConstantPoolEntries/EntryTag.cs index 11a4862..d47b641 100644 --- a/JavaAsm/IO/ConstantPoolEntries/EntryTag.cs +++ b/JavaAsm/IO/ConstantPoolEntries/EntryTag.cs @@ -1,7 +1,5 @@ -namespace JavaAsm.IO.ConstantPoolEntries -{ - internal enum EntryTag : byte - { +namespace JavaAsm.IO.ConstantPoolEntries { + internal enum EntryTag : byte { Class = 7, FieldReference = 9, MethodReference = 10, diff --git a/JavaAsm/IO/ConstantPoolEntries/FieldReferenceEntry.cs b/JavaAsm/IO/ConstantPoolEntries/FieldReferenceEntry.cs index 789b859..722518d 100644 --- a/JavaAsm/IO/ConstantPoolEntries/FieldReferenceEntry.cs +++ b/JavaAsm/IO/ConstantPoolEntries/FieldReferenceEntry.cs @@ -1,9 +1,7 @@ using System.IO; -namespace JavaAsm.IO.ConstantPoolEntries -{ - internal class FieldReferenceEntry : ReferenceEntry - { +namespace JavaAsm.IO.ConstantPoolEntries { + internal class FieldReferenceEntry : ReferenceEntry { public FieldReferenceEntry(ClassEntry @class, NameAndTypeEntry nameAndType) : base(@class, nameAndType) { } public override EntryTag Tag => EntryTag.FieldReference; diff --git a/JavaAsm/IO/ConstantPoolEntries/FloatEntry.cs b/JavaAsm/IO/ConstantPoolEntries/FloatEntry.cs index 1119c12..9e07a43 100644 --- a/JavaAsm/IO/ConstantPoolEntries/FloatEntry.cs +++ b/JavaAsm/IO/ConstantPoolEntries/FloatEntry.cs @@ -1,49 +1,50 @@ -using System; -using System.IO; +using System.IO; using BinaryEncoding; -namespace JavaAsm.IO.ConstantPoolEntries -{ - internal class FloatEntry : Entry - { +namespace JavaAsm.IO.ConstantPoolEntries { + internal class FloatEntry : Entry { public float Value { get; } - public FloatEntry(float value) - { - Value = value; + public FloatEntry(float value) { + this.Value = value; } - public FloatEntry(Stream stream) - { - Value = BitConverter.Int32BitsToSingle(Binary.BigEndian.ReadInt32(stream)); + public FloatEntry(Stream stream) { + unsafe { + int value = Binary.BigEndian.ReadInt32(stream); + // get address of value (as int*), cast to float*, get value from float* + this.Value = *(float*) &value; + } } public override EntryTag Tag => EntryTag.Float; public override void ProcessFromConstantPool(ConstantPool constantPool) { } - public override void Write(Stream stream) - { - Binary.BigEndian.Write(stream, BitConverter.SingleToInt32Bits(Value)); + public override void Write(Stream stream) { + unsafe { + float value = this.Value; + // get address of value (as float*), cast to int*, get value from int* + Binary.BigEndian.Write(stream, *(int*) &value); + } } public override void PutToConstantPool(ConstantPool constantPool) { } - private bool Equals(FloatEntry other) - { - return Value.Equals(other.Value); + private bool Equals(FloatEntry other) { + return this.Value.Equals(other.Value); } - public override bool Equals(object obj) - { - if (obj is null) return false; - if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == GetType() && Equals((FloatEntry)obj); + public override bool Equals(object obj) { + if (obj is null) + return false; + if (ReferenceEquals(this, obj)) + return true; + return obj.GetType() == GetType() && Equals((FloatEntry) obj); } - public override int GetHashCode() - { - return Value.GetHashCode(); + public override int GetHashCode() { + return this.Value.GetHashCode(); } } } \ No newline at end of file diff --git a/JavaAsm/IO/ConstantPoolEntries/IntegerEntry.cs b/JavaAsm/IO/ConstantPoolEntries/IntegerEntry.cs index 0be6fba..b47ac40 100644 --- a/JavaAsm/IO/ConstantPoolEntries/IntegerEntry.cs +++ b/JavaAsm/IO/ConstantPoolEntries/IntegerEntry.cs @@ -1,48 +1,42 @@ using System.IO; using BinaryEncoding; -namespace JavaAsm.IO.ConstantPoolEntries -{ - internal class IntegerEntry : Entry - { +namespace JavaAsm.IO.ConstantPoolEntries { + internal class IntegerEntry : Entry { public int Value { get; } - public IntegerEntry(int value) - { - Value = value; + public IntegerEntry(int value) { + this.Value = value; } - public IntegerEntry(Stream stream) - { - Value = Binary.BigEndian.ReadInt32(stream); + public IntegerEntry(Stream stream) { + this.Value = Binary.BigEndian.ReadInt32(stream); } public override EntryTag Tag => EntryTag.Integer; public override void ProcessFromConstantPool(ConstantPool constantPool) { } - public override void Write(Stream stream) - { - Binary.BigEndian.Write(stream, Value); + public override void Write(Stream stream) { + Binary.BigEndian.Write(stream, this.Value); } public override void PutToConstantPool(ConstantPool constantPool) { } - private bool Equals(IntegerEntry other) - { - return Value == other.Value; + private bool Equals(IntegerEntry other) { + return this.Value == other.Value; } - public override bool Equals(object obj) - { - if (obj is null) return false; - if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == GetType() && Equals((IntegerEntry)obj); + public override bool Equals(object obj) { + if (obj is null) + return false; + if (ReferenceEquals(this, obj)) + return true; + return obj.GetType() == GetType() && Equals((IntegerEntry) obj); } - public override int GetHashCode() - { - return Value; + public override int GetHashCode() { + return this.Value; } } } \ No newline at end of file diff --git a/JavaAsm/IO/ConstantPoolEntries/InterfaceMethodReferenceEntry.cs b/JavaAsm/IO/ConstantPoolEntries/InterfaceMethodReferenceEntry.cs index d9c89de..f7f6194 100644 --- a/JavaAsm/IO/ConstantPoolEntries/InterfaceMethodReferenceEntry.cs +++ b/JavaAsm/IO/ConstantPoolEntries/InterfaceMethodReferenceEntry.cs @@ -1,9 +1,7 @@ using System.IO; -namespace JavaAsm.IO.ConstantPoolEntries -{ - internal class InterfaceMethodReferenceEntry : MethodReferenceEntry - { +namespace JavaAsm.IO.ConstantPoolEntries { + internal class InterfaceMethodReferenceEntry : MethodReferenceEntry { public InterfaceMethodReferenceEntry(ClassEntry @class, NameAndTypeEntry nameAndType) : base(@class, nameAndType) { } public override EntryTag Tag => EntryTag.InterfaceMethodReference; diff --git a/JavaAsm/IO/ConstantPoolEntries/InvokeDynamicEntry.cs b/JavaAsm/IO/ConstantPoolEntries/InvokeDynamicEntry.cs index dfa4908..34afbc7 100644 --- a/JavaAsm/IO/ConstantPoolEntries/InvokeDynamicEntry.cs +++ b/JavaAsm/IO/ConstantPoolEntries/InvokeDynamicEntry.cs @@ -3,63 +3,54 @@ using System.IO; using BinaryEncoding; -namespace JavaAsm.IO.ConstantPoolEntries -{ - internal class InvokeDynamicEntry : Entry - { +namespace JavaAsm.IO.ConstantPoolEntries { + internal class InvokeDynamicEntry : Entry { public ushort BootstrapMethodAttributeIndex { get; } public NameAndTypeEntry NameAndType { get; private set; } private ushort nameAndTypeIndex; - public InvokeDynamicEntry(ushort bootstrapMethodAttributeIndex, NameAndTypeEntry nameAndType) - { - BootstrapMethodAttributeIndex = bootstrapMethodAttributeIndex; - NameAndType = nameAndType ?? throw new ArgumentNullException(nameof(nameAndType)); + public InvokeDynamicEntry(ushort bootstrapMethodAttributeIndex, NameAndTypeEntry nameAndType) { + this.BootstrapMethodAttributeIndex = bootstrapMethodAttributeIndex; + this.NameAndType = nameAndType ?? throw new ArgumentNullException(nameof(nameAndType)); } - public InvokeDynamicEntry(Stream stream) - { - BootstrapMethodAttributeIndex = Binary.BigEndian.ReadUInt16(stream); - nameAndTypeIndex = Binary.BigEndian.ReadUInt16(stream); + public InvokeDynamicEntry(Stream stream) { + this.BootstrapMethodAttributeIndex = Binary.BigEndian.ReadUInt16(stream); + this.nameAndTypeIndex = Binary.BigEndian.ReadUInt16(stream); } public override EntryTag Tag => EntryTag.InvokeDynamic; - public override void ProcessFromConstantPool(ConstantPool constantPool) - { - NameAndType = constantPool.GetEntry(nameAndTypeIndex); + public override void ProcessFromConstantPool(ConstantPool constantPool) { + this.NameAndType = constantPool.GetEntry(this.nameAndTypeIndex); } - public override void Write(Stream stream) - { - Binary.BigEndian.Write(stream, BootstrapMethodAttributeIndex); - Binary.BigEndian.Write(stream, nameAndTypeIndex); + public override void Write(Stream stream) { + Binary.BigEndian.Write(stream, this.BootstrapMethodAttributeIndex); + Binary.BigEndian.Write(stream, this.nameAndTypeIndex); } - public override void PutToConstantPool(ConstantPool constantPool) - { - nameAndTypeIndex = constantPool.Find(NameAndType); + public override void PutToConstantPool(ConstantPool constantPool) { + this.nameAndTypeIndex = constantPool.Find(this.NameAndType); } - private bool Equals(InvokeDynamicEntry other) - { - return BootstrapMethodAttributeIndex == other.BootstrapMethodAttributeIndex && Equals(NameAndType, other.NameAndType); + private bool Equals(InvokeDynamicEntry other) { + return this.BootstrapMethodAttributeIndex == other.BootstrapMethodAttributeIndex && Equals(this.NameAndType, other.NameAndType); } - public override bool Equals(object obj) - { - if (obj is null) return false; - if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == GetType() && Equals((InvokeDynamicEntry)obj); + public override bool Equals(object obj) { + if (obj is null) + return false; + if (ReferenceEquals(this, obj)) + return true; + return obj.GetType() == GetType() && Equals((InvokeDynamicEntry) obj); } [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] - public override int GetHashCode() - { - unchecked - { - return (BootstrapMethodAttributeIndex.GetHashCode() * 397) ^ (NameAndType != null ? NameAndType.GetHashCode() : 0); + public override int GetHashCode() { + unchecked { + return (this.BootstrapMethodAttributeIndex.GetHashCode() * 397) ^ (this.NameAndType != null ? this.NameAndType.GetHashCode() : 0); } } } diff --git a/JavaAsm/IO/ConstantPoolEntries/LongEntry.cs b/JavaAsm/IO/ConstantPoolEntries/LongEntry.cs index d980e7f..5dca14f 100644 --- a/JavaAsm/IO/ConstantPoolEntries/LongEntry.cs +++ b/JavaAsm/IO/ConstantPoolEntries/LongEntry.cs @@ -1,48 +1,42 @@ using System.IO; using BinaryEncoding; -namespace JavaAsm.IO.ConstantPoolEntries -{ - internal class LongEntry : Entry - { +namespace JavaAsm.IO.ConstantPoolEntries { + internal class LongEntry : Entry { public long Value { get; } - public LongEntry(long value) - { - Value = value; + public LongEntry(long value) { + this.Value = value; } - public LongEntry(Stream stream) - { - Value = Binary.BigEndian.ReadInt64(stream); + public LongEntry(Stream stream) { + this.Value = Binary.BigEndian.ReadInt64(stream); } public override EntryTag Tag => EntryTag.Long; public override void ProcessFromConstantPool(ConstantPool constantPool) { } - public override void Write(Stream stream) - { - Binary.BigEndian.Write(stream, Value); + public override void Write(Stream stream) { + Binary.BigEndian.Write(stream, this.Value); } public override void PutToConstantPool(ConstantPool constantPool) { } - private bool Equals(LongEntry other) - { - return Value == other.Value; + private bool Equals(LongEntry other) { + return this.Value == other.Value; } - public override bool Equals(object obj) - { - if (obj is null) return false; - if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == GetType() && Equals((LongEntry)obj); + public override bool Equals(object obj) { + if (obj is null) + return false; + if (ReferenceEquals(this, obj)) + return true; + return obj.GetType() == GetType() && Equals((LongEntry) obj); } - public override int GetHashCode() - { - return Value.GetHashCode(); + public override int GetHashCode() { + return this.Value.GetHashCode(); } } } \ No newline at end of file diff --git a/JavaAsm/IO/ConstantPoolEntries/MethodHandleEntry.cs b/JavaAsm/IO/ConstantPoolEntries/MethodHandleEntry.cs index 0ebeffd..f138850 100644 --- a/JavaAsm/IO/ConstantPoolEntries/MethodHandleEntry.cs +++ b/JavaAsm/IO/ConstantPoolEntries/MethodHandleEntry.cs @@ -5,91 +5,79 @@ using JavaAsm.Helpers; using JavaAsm.Instructions.Types; -namespace JavaAsm.IO.ConstantPoolEntries -{ - internal class MethodHandleEntry : Entry - { +namespace JavaAsm.IO.ConstantPoolEntries { + internal class MethodHandleEntry : Entry { public ReferenceKindType ReferenceKind { get; } public ReferenceEntry Reference { get; private set; } private ushort referenceIndex; - public MethodHandleEntry(ReferenceKindType referenceKind, ReferenceEntry reference) - { - ReferenceKind = referenceKind; - Reference = reference ?? throw new ArgumentNullException(nameof(reference)); + public MethodHandleEntry(ReferenceKindType referenceKind, ReferenceEntry reference) { + this.ReferenceKind = referenceKind; + this.Reference = reference ?? throw new ArgumentNullException(nameof(reference)); } - public MethodHandleEntry(Stream stream) - { - ReferenceKind = (ReferenceKindType) stream.ReadByteFully(); - referenceIndex = Binary.BigEndian.ReadUInt16(stream); + public MethodHandleEntry(Stream stream) { + this.ReferenceKind = (ReferenceKindType) stream.ReadByteFully(); + this.referenceIndex = Binary.BigEndian.ReadUInt16(stream); } public override EntryTag Tag => EntryTag.MethodHandle; - public override void ProcessFromConstantPool(ConstantPool constantPool) - { - switch (ReferenceKind) - { + public override void ProcessFromConstantPool(ConstantPool constantPool) { + switch (this.ReferenceKind) { case ReferenceKindType.GetField: case ReferenceKindType.GetStatic: case ReferenceKindType.PutField: case ReferenceKindType.PutStatic: - Reference = constantPool.GetEntry(referenceIndex); + this.Reference = constantPool.GetEntry(this.referenceIndex); break; case ReferenceKindType.InvokeVirtual: case ReferenceKindType.NewInvokeSpecial: - Reference = constantPool.GetEntry(referenceIndex); + this.Reference = constantPool.GetEntry(this.referenceIndex); break; case ReferenceKindType.InvokeStatic: case ReferenceKindType.InvokeSpecial: - try - { - Reference = constantPool.GetEntry(referenceIndex); + try { + this.Reference = constantPool.GetEntry(this.referenceIndex); } - catch (InvalidCastException) - { - Reference = constantPool.GetEntry(referenceIndex); + catch (InvalidCastException) { + this.Reference = constantPool.GetEntry(this.referenceIndex); } + break; case ReferenceKindType.InvokeReference: - Reference = constantPool.GetEntry(referenceIndex); + this.Reference = constantPool.GetEntry(this.referenceIndex); break; - default: - throw new ArgumentOutOfRangeException(nameof(ReferenceKind)); + default: throw new ArgumentOutOfRangeException(nameof(this.ReferenceKind)); } } - public override void Write(Stream stream) - { - stream.WriteByte((byte)ReferenceKind); - Binary.BigEndian.Write(stream, referenceIndex); + public override void Write(Stream stream) { + stream.WriteByte((byte) this.ReferenceKind); + Binary.BigEndian.Write(stream, this.referenceIndex); } - public override void PutToConstantPool(ConstantPool constantPool) - { - referenceIndex = constantPool.Find(Reference); + public override void PutToConstantPool(ConstantPool constantPool) { + this.referenceIndex = constantPool.Find(this.Reference); } - private bool Equals(MethodHandleEntry other) - { - return ReferenceKind == other.ReferenceKind && Equals(Reference, other.Reference); + private bool Equals(MethodHandleEntry other) { + return this.ReferenceKind == other.ReferenceKind && Equals(this.Reference, other.Reference); } - public override bool Equals(object obj) - { - if (obj is null) return false; - if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == GetType() && Equals((MethodHandleEntry)obj); + public override bool Equals(object obj) { + if (obj is null) + return false; + if (ReferenceEquals(this, obj)) + return true; + return obj.GetType() == GetType() && Equals((MethodHandleEntry) obj); } [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] - public override int GetHashCode() - { - unchecked - { - return ((int)ReferenceKind * 397) ^ (Reference != null ? Reference.GetHashCode() : 0); + public override int GetHashCode() { + unchecked { + return ((int) this.ReferenceKind * 397) ^ (this.Reference != null ? this.Reference.GetHashCode() : 0); } } } diff --git a/JavaAsm/IO/ConstantPoolEntries/MethodReferenceEntry.cs b/JavaAsm/IO/ConstantPoolEntries/MethodReferenceEntry.cs index 717c008..f17c13f 100644 --- a/JavaAsm/IO/ConstantPoolEntries/MethodReferenceEntry.cs +++ b/JavaAsm/IO/ConstantPoolEntries/MethodReferenceEntry.cs @@ -1,9 +1,7 @@ using System.IO; -namespace JavaAsm.IO.ConstantPoolEntries -{ - internal class MethodReferenceEntry : ReferenceEntry - { +namespace JavaAsm.IO.ConstantPoolEntries { + internal class MethodReferenceEntry : ReferenceEntry { public MethodReferenceEntry(ClassEntry @class, NameAndTypeEntry nameAndType) : base(@class, nameAndType) { } public override EntryTag Tag => EntryTag.MethodReference; diff --git a/JavaAsm/IO/ConstantPoolEntries/MethodTypeEntry.cs b/JavaAsm/IO/ConstantPoolEntries/MethodTypeEntry.cs index 9b85057..808dd8c 100644 --- a/JavaAsm/IO/ConstantPoolEntries/MethodTypeEntry.cs +++ b/JavaAsm/IO/ConstantPoolEntries/MethodTypeEntry.cs @@ -3,56 +3,48 @@ using System.IO; using BinaryEncoding; -namespace JavaAsm.IO.ConstantPoolEntries -{ - internal class MethodTypeEntry : Entry - { +namespace JavaAsm.IO.ConstantPoolEntries { + internal class MethodTypeEntry : Entry { public Utf8Entry Descriptor { get; private set; } private ushort descriptorIndex; - public MethodTypeEntry(Utf8Entry descriptor) - { - Descriptor = descriptor ?? throw new ArgumentNullException(nameof(descriptor)); + public MethodTypeEntry(Utf8Entry descriptor) { + this.Descriptor = descriptor ?? throw new ArgumentNullException(nameof(descriptor)); } - public MethodTypeEntry(Stream stream) - { - descriptorIndex = Binary.BigEndian.ReadUInt16(stream); + public MethodTypeEntry(Stream stream) { + this.descriptorIndex = Binary.BigEndian.ReadUInt16(stream); } public override EntryTag Tag => EntryTag.MethodType; - public override void ProcessFromConstantPool(ConstantPool constantPool) - { - Descriptor = constantPool.GetEntry(descriptorIndex); + public override void ProcessFromConstantPool(ConstantPool constantPool) { + this.Descriptor = constantPool.GetEntry(this.descriptorIndex); } - public override void Write(Stream stream) - { - Binary.BigEndian.Write(stream, descriptorIndex); + public override void Write(Stream stream) { + Binary.BigEndian.Write(stream, this.descriptorIndex); } - public override void PutToConstantPool(ConstantPool constantPool) - { - descriptorIndex = constantPool.Find(Descriptor); + public override void PutToConstantPool(ConstantPool constantPool) { + this.descriptorIndex = constantPool.Find(this.Descriptor); } - private bool Equals(MethodTypeEntry other) - { - return Equals(Descriptor, other.Descriptor); + private bool Equals(MethodTypeEntry other) { + return Equals(this.Descriptor, other.Descriptor); } - public override bool Equals(object obj) - { - if (obj is null) return false; - if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == GetType() && Equals((MethodTypeEntry)obj); + public override bool Equals(object obj) { + if (obj is null) + return false; + if (ReferenceEquals(this, obj)) + return true; + return obj.GetType() == GetType() && Equals((MethodTypeEntry) obj); } [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] - public override int GetHashCode() - { - return Descriptor != null ? Descriptor.GetHashCode() : 0; + public override int GetHashCode() { + return this.Descriptor != null ? this.Descriptor.GetHashCode() : 0; } } } \ No newline at end of file diff --git a/JavaAsm/IO/ConstantPoolEntries/NameAndTypeEntry.cs b/JavaAsm/IO/ConstantPoolEntries/NameAndTypeEntry.cs index 64e52c0..9482d48 100644 --- a/JavaAsm/IO/ConstantPoolEntries/NameAndTypeEntry.cs +++ b/JavaAsm/IO/ConstantPoolEntries/NameAndTypeEntry.cs @@ -3,66 +3,57 @@ using System.IO; using BinaryEncoding; -namespace JavaAsm.IO.ConstantPoolEntries -{ - internal class NameAndTypeEntry : Entry - { +namespace JavaAsm.IO.ConstantPoolEntries { + internal class NameAndTypeEntry : Entry { public Utf8Entry Name { get; private set; } private ushort nameIndex; public Utf8Entry Descriptor { get; private set; } private ushort descriptorIndex; - public NameAndTypeEntry(Utf8Entry name, Utf8Entry descriptor) - { - Name = name ?? throw new ArgumentNullException(nameof(name)); - Descriptor = descriptor ?? throw new ArgumentNullException(nameof(descriptor)); + public NameAndTypeEntry(Utf8Entry name, Utf8Entry descriptor) { + this.Name = name ?? throw new ArgumentNullException(nameof(name)); + this.Descriptor = descriptor ?? throw new ArgumentNullException(nameof(descriptor)); } - public NameAndTypeEntry(Stream stream) - { - nameIndex = Binary.BigEndian.ReadUInt16(stream); - descriptorIndex = Binary.BigEndian.ReadUInt16(stream); + public NameAndTypeEntry(Stream stream) { + this.nameIndex = Binary.BigEndian.ReadUInt16(stream); + this.descriptorIndex = Binary.BigEndian.ReadUInt16(stream); } public override EntryTag Tag => EntryTag.NameAndType; - public override void ProcessFromConstantPool(ConstantPool constantPool) - { - Name = constantPool.GetEntry(nameIndex); - Descriptor = constantPool.GetEntry(descriptorIndex); + public override void ProcessFromConstantPool(ConstantPool constantPool) { + this.Name = constantPool.GetEntry(this.nameIndex); + this.Descriptor = constantPool.GetEntry(this.descriptorIndex); } - public override void Write(Stream stream) - { - Binary.BigEndian.Write(stream, nameIndex); - Binary.BigEndian.Write(stream, descriptorIndex); + public override void Write(Stream stream) { + Binary.BigEndian.Write(stream, this.nameIndex); + Binary.BigEndian.Write(stream, this.descriptorIndex); } - public override void PutToConstantPool(ConstantPool constantPool) - { - nameIndex = constantPool.Find(Name); - descriptorIndex = constantPool.Find(Descriptor); + public override void PutToConstantPool(ConstantPool constantPool) { + this.nameIndex = constantPool.Find(this.Name); + this.descriptorIndex = constantPool.Find(this.Descriptor); } - private bool Equals(NameAndTypeEntry other) - { - return Name.Equals(other.Name) && Descriptor.Equals(other.Descriptor); + private bool Equals(NameAndTypeEntry other) { + return this.Name.Equals(other.Name) && this.Descriptor.Equals(other.Descriptor); } - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == GetType() && Equals((NameAndTypeEntry)obj); + public override bool Equals(object obj) { + if (ReferenceEquals(null, obj)) + return false; + if (ReferenceEquals(this, obj)) + return true; + return obj.GetType() == GetType() && Equals((NameAndTypeEntry) obj); } [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] - public override int GetHashCode() - { - unchecked - { - return (Name.GetHashCode() * 397) ^ Descriptor.GetHashCode(); + public override int GetHashCode() { + unchecked { + return (this.Name.GetHashCode() * 397) ^ this.Descriptor.GetHashCode(); } } } diff --git a/JavaAsm/IO/ConstantPoolEntries/ReferenceEntry.cs b/JavaAsm/IO/ConstantPoolEntries/ReferenceEntry.cs index 6978759..cfafa0c 100644 --- a/JavaAsm/IO/ConstantPoolEntries/ReferenceEntry.cs +++ b/JavaAsm/IO/ConstantPoolEntries/ReferenceEntry.cs @@ -3,64 +3,55 @@ using System.IO; using BinaryEncoding; -namespace JavaAsm.IO.ConstantPoolEntries -{ - internal abstract class ReferenceEntry : Entry - { +namespace JavaAsm.IO.ConstantPoolEntries { + internal abstract class ReferenceEntry : Entry { public ClassEntry Class { get; private set; } private ushort classIndex; public NameAndTypeEntry NameAndType { get; private set; } private ushort nameAndTypeIndex; - protected ReferenceEntry(ClassEntry @class, NameAndTypeEntry nameAndType) - { - Class = @class ?? throw new ArgumentNullException(nameof(@class)); - NameAndType = nameAndType ?? throw new ArgumentNullException(nameof(nameAndType)); + protected ReferenceEntry(ClassEntry @class, NameAndTypeEntry nameAndType) { + this.Class = @class ?? throw new ArgumentNullException(nameof(@class)); + this.NameAndType = nameAndType ?? throw new ArgumentNullException(nameof(nameAndType)); } - protected ReferenceEntry(Stream stream) - { - classIndex = Binary.BigEndian.ReadUInt16(stream); - nameAndTypeIndex = Binary.BigEndian.ReadUInt16(stream); + protected ReferenceEntry(Stream stream) { + this.classIndex = Binary.BigEndian.ReadUInt16(stream); + this.nameAndTypeIndex = Binary.BigEndian.ReadUInt16(stream); } - public override void ProcessFromConstantPool(ConstantPool constantPool) - { - Class = constantPool.GetEntry(classIndex); - NameAndType = constantPool.GetEntry(nameAndTypeIndex); + public override void ProcessFromConstantPool(ConstantPool constantPool) { + this.Class = constantPool.GetEntry(this.classIndex); + this.NameAndType = constantPool.GetEntry(this.nameAndTypeIndex); } - public override void Write(Stream stream) - { - Binary.BigEndian.Write(stream, classIndex); - Binary.BigEndian.Write(stream, nameAndTypeIndex); + public override void Write(Stream stream) { + Binary.BigEndian.Write(stream, this.classIndex); + Binary.BigEndian.Write(stream, this.nameAndTypeIndex); } - public override void PutToConstantPool(ConstantPool constantPool) - { - classIndex = constantPool.Find(Class); - nameAndTypeIndex = constantPool.Find(NameAndType); + public override void PutToConstantPool(ConstantPool constantPool) { + this.classIndex = constantPool.Find(this.Class); + this.nameAndTypeIndex = constantPool.Find(this.NameAndType); } - private bool Equals(ReferenceEntry other) - { - return Class.Equals(other.Class) && NameAndType.Equals(other.NameAndType); + private bool Equals(ReferenceEntry other) { + return this.Class.Equals(other.Class) && this.NameAndType.Equals(other.NameAndType); } - public override bool Equals(object obj) - { - if (obj is null) return false; - if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == GetType() && Equals((ReferenceEntry)obj); + public override bool Equals(object obj) { + if (obj is null) + return false; + if (ReferenceEquals(this, obj)) + return true; + return obj.GetType() == GetType() && Equals((ReferenceEntry) obj); } [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] - public override int GetHashCode() - { - unchecked - { - return (Class.GetHashCode() * 397) ^ NameAndType.GetHashCode(); + public override int GetHashCode() { + unchecked { + return (this.Class.GetHashCode() * 397) ^ this.NameAndType.GetHashCode(); } } } diff --git a/JavaAsm/IO/ConstantPoolEntries/StringEntry.cs b/JavaAsm/IO/ConstantPoolEntries/StringEntry.cs index 19a3441..638d4c8 100644 --- a/JavaAsm/IO/ConstantPoolEntries/StringEntry.cs +++ b/JavaAsm/IO/ConstantPoolEntries/StringEntry.cs @@ -3,56 +3,48 @@ using System.IO; using BinaryEncoding; -namespace JavaAsm.IO.ConstantPoolEntries -{ - internal class StringEntry : Entry - { +namespace JavaAsm.IO.ConstantPoolEntries { + internal class StringEntry : Entry { public Utf8Entry Value { get; private set; } private ushort nameIndex; - public StringEntry(Utf8Entry @string) - { - Value = @string ?? throw new ArgumentNullException(nameof(@string)); + public StringEntry(Utf8Entry @string) { + this.Value = @string ?? throw new ArgumentNullException(nameof(@string)); } - public StringEntry(Stream stream) - { - nameIndex = Binary.BigEndian.ReadUInt16(stream); + public StringEntry(Stream stream) { + this.nameIndex = Binary.BigEndian.ReadUInt16(stream); } public override EntryTag Tag => EntryTag.String; - public override void ProcessFromConstantPool(ConstantPool constantPool) - { - Value = constantPool.GetEntry(nameIndex); + public override void ProcessFromConstantPool(ConstantPool constantPool) { + this.Value = constantPool.GetEntry(this.nameIndex); } - public override void Write(Stream stream) - { - Binary.BigEndian.Write(stream, nameIndex); + public override void Write(Stream stream) { + Binary.BigEndian.Write(stream, this.nameIndex); } - public override void PutToConstantPool(ConstantPool constantPool) - { - nameIndex = constantPool.Find(Value); + public override void PutToConstantPool(ConstantPool constantPool) { + this.nameIndex = constantPool.Find(this.Value); } - private bool Equals(StringEntry other) - { - return Value.Equals(other.Value); + private bool Equals(StringEntry other) { + return this.Value.Equals(other.Value); } - public override bool Equals(object obj) - { - if (obj is null) return false; - if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == GetType() && Equals((StringEntry)obj); + public override bool Equals(object obj) { + if (obj is null) + return false; + if (ReferenceEquals(this, obj)) + return true; + return obj.GetType() == GetType() && Equals((StringEntry) obj); } [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] - public override int GetHashCode() - { - return Value.GetHashCode(); + public override int GetHashCode() { + return this.Value.GetHashCode(); } } } \ No newline at end of file diff --git a/JavaAsm/IO/ConstantPoolEntries/Utf8Entry.cs b/JavaAsm/IO/ConstantPoolEntries/Utf8Entry.cs index b2601ff..f0aaa04 100644 --- a/JavaAsm/IO/ConstantPoolEntries/Utf8Entry.cs +++ b/JavaAsm/IO/ConstantPoolEntries/Utf8Entry.cs @@ -3,51 +3,45 @@ using BinaryEncoding; using JavaAsm.Helpers; -namespace JavaAsm.IO.ConstantPoolEntries -{ - internal class Utf8Entry : Entry - { +namespace JavaAsm.IO.ConstantPoolEntries { + internal class Utf8Entry : Entry { public string String { get; } - public Utf8Entry(string @string) - { - String = @string ?? throw new ArgumentNullException(nameof(@string)); + public Utf8Entry(string @string) { + this.String = @string ?? throw new ArgumentNullException(nameof(@string)); } - public Utf8Entry(Stream stream) - { - var data = new byte[Binary.BigEndian.ReadUInt16(stream)]; - stream.Read(data); - String = ModifiedUtf8Helper.Decode(data); + public Utf8Entry(Stream stream) { + byte[] data = new byte[Binary.BigEndian.ReadUInt16(stream)]; + stream.Read(data, 0, data.Length); + this.String = ModifiedUtf8Helper.Decode(data); } public override EntryTag Tag => EntryTag.Utf8; public override void ProcessFromConstantPool(ConstantPool constantPool) { } - public override void Write(Stream stream) - { - Binary.BigEndian.Write(stream, ModifiedUtf8Helper.GetBytesCount(String)); - stream.Write(ModifiedUtf8Helper.Encode(String)); + public override void Write(Stream stream) { + Binary.BigEndian.Write(stream, ModifiedUtf8Helper.GetBytesCount(this.String)); + stream.Write(ModifiedUtf8Helper.Encode(this.String)); } public override void PutToConstantPool(ConstantPool constantPool) { } - private bool Equals(Utf8Entry other) - { - return String == other.String; + private bool Equals(Utf8Entry other) { + return this.String == other.String; } - public override bool Equals(object obj) - { - if (obj is null) return false; - if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == GetType() && Equals((Utf8Entry)obj); + public override bool Equals(object obj) { + if (obj is null) + return false; + if (ReferenceEquals(this, obj)) + return true; + return obj.GetType() == GetType() && Equals((Utf8Entry) obj); } - public override int GetHashCode() - { - return String.GetHashCode(); + public override int GetHashCode() { + return this.String.GetHashCode(); } } } \ No newline at end of file diff --git a/JavaAsm/Instructions/Instruction.cs b/JavaAsm/Instructions/Instruction.cs index b99f3ba..8f56492 100644 --- a/JavaAsm/Instructions/Instruction.cs +++ b/JavaAsm/Instructions/Instruction.cs @@ -1,13 +1,13 @@ -namespace JavaAsm.Instructions -{ - public abstract class Instruction - { +namespace JavaAsm.Instructions { + public abstract class Instruction { public InstructionList OwnerList { get; internal set; } public Instruction Previous { get; internal set; } public Instruction Next { get; internal set; } - public abstract Opcode Opcode { get; } + public abstract Opcode Opcode { get; set; } + + public abstract Instruction Copy(); } -} +} \ No newline at end of file diff --git a/JavaAsm/Instructions/InstructionList.cs b/JavaAsm/Instructions/InstructionList.cs index 2433564..4a2a37c 100644 --- a/JavaAsm/Instructions/InstructionList.cs +++ b/JavaAsm/Instructions/InstructionList.cs @@ -2,40 +2,34 @@ using System.Collections; using System.Collections.Generic; -namespace JavaAsm.Instructions -{ - public class InstructionList : IEnumerable - { - private class InstructionListEnumerator : IEnumerator - { - public InstructionListEnumerator(Instruction start) - { - Start = start; +namespace JavaAsm.Instructions { + public class InstructionList : IEnumerable { + private class InstructionListEnumerator : IEnumerator { + public InstructionListEnumerator(Instruction start) { + this.Start = start; } - public bool MoveNext() - { - if (Start != null && Current == null) - { - Current = Start; + public bool MoveNext() { + if (this.Start != null && this.Current == null) { + this.Current = this.Start; return true; } - if (Current?.Next == null) + + if (this.Current?.Next == null) return false; - Current = Current.Next; + this.Current = this.Current.Next; return true; } - public void Reset() - { - Current = null; + public void Reset() { + this.Current = null; } public Instruction Current { get; private set; } private Instruction Start { get; } - object IEnumerator.Current => Current; + object IEnumerator.Current => this.Current; public void Dispose() { } } @@ -46,21 +40,19 @@ public void Dispose() { } public int Count { get; private set; } - public void Add(Instruction instruction) - { + public void Add(Instruction instruction) { instruction.OwnerList = this; instruction.Next = null; - if (First == null) - First = instruction; - instruction.Previous = Last; - Last = instruction; + if (this.First == null) + this.First = instruction; + instruction.Previous = this.Last; + this.Last = instruction; if (instruction.Previous != null) instruction.Previous.Next = instruction; - Count++; + this.Count++; } - public void InsertBefore(Instruction instruction, Instruction toInsert) - { + public void InsertBefore(Instruction instruction, Instruction toInsert) { if (instruction.OwnerList != this) throw new ArgumentException("Position instruction does not belong to that list", nameof(instruction.OwnerList)); toInsert.OwnerList = this; @@ -71,13 +63,12 @@ public void InsertBefore(Instruction instruction, Instruction toInsert) toInsert.Previous.Next = toInsert; toInsert.Next.Previous = toInsert; - if (ReferenceEquals(instruction, First)) - First = toInsert; - Count++; + if (ReferenceEquals(instruction, this.First)) + this.First = toInsert; + this.Count++; } - public void InsertAfter(Instruction instruction, Instruction toInsert) - { + public void InsertAfter(Instruction instruction, Instruction toInsert) { if (instruction.OwnerList != this) throw new ArgumentException("Position instruction does not belong to that list", nameof(instruction.OwnerList)); toInsert.OwnerList = this; @@ -88,13 +79,12 @@ public void InsertAfter(Instruction instruction, Instruction toInsert) toInsert.Next.Previous = toInsert; toInsert.Previous.Next = toInsert; - if (ReferenceEquals(instruction, Last)) - Last = toInsert; - Count++; + if (ReferenceEquals(instruction, this.Last)) + this.Last = toInsert; + this.Count++; } - public void Remove(Instruction instruction) - { + public void Remove(Instruction instruction) { if (instruction.OwnerList != this) throw new ArgumentException("Instruction does not belong to that list", nameof(instruction.OwnerList)); instruction.OwnerList = null; @@ -102,21 +92,32 @@ public void Remove(Instruction instruction) instruction.Next.Previous = instruction.Previous; if (instruction.Previous != null) instruction.Previous.Next = instruction.Next; - if (ReferenceEquals(instruction, First)) - First = instruction.Next; - if (ReferenceEquals(instruction, Last)) - Last = instruction.Previous; - Count--; + if (ReferenceEquals(instruction, this.First)) + this.First = instruction.Next; + if (ReferenceEquals(instruction, this.Last)) + this.Last = instruction.Previous; + this.Count--; } - public IEnumerator GetEnumerator() - { - return new InstructionListEnumerator(First); + // public void Clear() { + // Instruction current = this.First; + // while (current != null) { + // Instruction temp = current; + // current = current.Next; + // temp.Next = null; + // temp.Previous = null; + // temp.OwnerList = null; + // } + // this.First = null; + // this.Count = 0; + // } + + public IEnumerator GetEnumerator() { + return new InstructionListEnumerator(this.First); } - IEnumerator IEnumerable.GetEnumerator() - { + IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } -} +} \ No newline at end of file diff --git a/JavaAsm/Instructions/InstructionListConverter.cs b/JavaAsm/Instructions/InstructionListConverter.cs index 82a43cc..a53e9e7 100644 --- a/JavaAsm/Instructions/InstructionListConverter.cs +++ b/JavaAsm/Instructions/InstructionListConverter.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.IO; using System.Linq; +using System.Text; using BinaryEncoding; using JavaAsm.CustomAttributes; using JavaAsm.Helpers; @@ -9,20 +11,18 @@ using JavaAsm.IO; using JavaAsm.IO.ConstantPoolEntries; -namespace JavaAsm.Instructions -{ - internal static class InstructionListConverter - { - private static AttributeNode GetAttribute(ICollection attributes, string name) - { - var attribute = attributes.FirstOrDefault(a => a.Name == name); +namespace JavaAsm.Instructions { + internal static class InstructionListConverter { + private static AttributeNode GetAttribute(ICollection attributes, string name) { + AttributeNode attribute = attributes.FirstOrDefault(a => a.Name == name); if (attribute != null) attributes.Remove(attribute); return attribute; } - public static void ParseCodeAttribute(MethodNode parseTo, ClassReaderState readerState, CodeAttribute codeAttribute) - { + public static void ParseCodeAttribute(MethodNode parseTo, ClassReaderState readerState, CodeAttribute codeAttribute) { + Label.GlobalLabelIndex = 0; + parseTo.MaxStack = codeAttribute.MaxStack; parseTo.MaxLocals = codeAttribute.MaxLocals; parseTo.CodeAttributes = codeAttribute.Attributes; @@ -30,22 +30,19 @@ public static void ParseCodeAttribute(MethodNode parseTo, ClassReaderState reade if (codeAttribute.Code.Length == 0) return; - var bootstrapMethodsAttribute = readerState.ClassNode.Attributes - .FirstOrDefault(x => x.Name == PredefinedAttributeNames.BootstrapMethods)?.ParsedAttribute as BootstrapMethodsAttribute; + BootstrapMethodsAttribute bootstrapMethodsAttribute = readerState.ClassNode.Attributes.FirstOrDefault(x => x.Name == PredefinedAttributeNames.BootstrapMethods)?.ParsedAttribute as BootstrapMethodsAttribute; - var instructions = new Dictionary(); - var labels = new Dictionary(); + Dictionary instructions = new Dictionary(); + Dictionary labels = new Dictionary(); - var wideFlag = false; + bool wideFlag = false; - using var codeStream = new MemoryStream(codeAttribute.Code); - while (codeStream.Position != codeStream.Length) - { - var currentPosition = codeStream.Position; + MemoryStream codeStream = new MemoryStream(codeAttribute.Code); + while (codeStream.Position != codeStream.Length) { + long currentPosition = codeStream.Position; - var opcode = (Opcode) codeStream.ReadByteFully(); - switch (opcode) - { + Opcode opcode = (Opcode) codeStream.ReadByteFully(); + switch (opcode) { case Opcode.NOP: case Opcode.ACONST_NULL: case Opcode.ICONST_M1: @@ -173,72 +170,65 @@ public static void ParseCodeAttribute(MethodNode parseTo, ClassReaderState reade case Opcode.GOTO: case Opcode.JSR: case Opcode.IFNULL: - case Opcode.IFNONNULL: - { - instructions.Add(currentPosition, new JumpInstruction(opcode) - { - Target = labels.GetOrAdd(currentPosition + Binary.BigEndian.ReadInt16(codeStream), new Label()) - }); - } + case Opcode.IFNONNULL: { + int jumpOffset = Binary.BigEndian.ReadInt16(codeStream); + instructions.Add(currentPosition, new JumpInstruction(opcode) { + Target = labels.GetOrAdd(currentPosition + jumpOffset, () => new Label()), + JumpOffset = jumpOffset + }); + } break; case Opcode.JSR_W: - case Opcode.GOTO_W: - { - instructions.Add(currentPosition, new JumpInstruction(opcode == Opcode.JSR_W ? Opcode.JSR : Opcode.GOTO) - { - Target = labels.GetOrAdd(currentPosition + Binary.BigEndian.ReadInt32(codeStream), new Label()) - }); - } + case Opcode.GOTO_W: { + int jumpOffset = Binary.BigEndian.ReadInt32(codeStream); + instructions.Add(currentPosition, new JumpInstruction(opcode == Opcode.JSR_W ? Opcode.JSR : Opcode.GOTO) { + Target = labels.GetOrAdd(currentPosition + jumpOffset, () => new Label()), + JumpOffset = jumpOffset + }); + } break; - case Opcode.LOOKUPSWITCH: - { - while (codeStream.Position % 4 != 0) - codeStream.ReadByteFully(); - var lookupSwitchInstruction = new LookupSwitchInstruction - { - Default = labels.GetOrAdd(currentPosition + Binary.BigEndian.ReadInt32(codeStream), new Label()) - }; - var nPairs = Binary.BigEndian.ReadInt32(codeStream); - lookupSwitchInstruction.MatchLabels.Capacity = nPairs; - for (var i = 0; i < nPairs; i++) - { - lookupSwitchInstruction.MatchLabels.Add(new KeyValuePair( - Binary.BigEndian.ReadInt32(codeStream), - labels.GetOrAdd(currentPosition + Binary.BigEndian.ReadInt32(codeStream), new Label()))); - } - - instructions.Add(currentPosition, lookupSwitchInstruction); + case Opcode.LOOKUPSWITCH: { + while (codeStream.Position % 4 != 0) + codeStream.ReadByteFully(); + LookupSwitchInstruction lookupSwitchInstruction = new LookupSwitchInstruction { + Default = labels.GetOrAdd(currentPosition + Binary.BigEndian.ReadInt32(codeStream), () => new Label()) + }; + int nPairs = Binary.BigEndian.ReadInt32(codeStream); + lookupSwitchInstruction.MatchLabels.Capacity = nPairs; + for (int i = 0; i < nPairs; i++) { + lookupSwitchInstruction.MatchLabels.Add(new KeyValuePair( + Binary.BigEndian.ReadInt32(codeStream), + labels.GetOrAdd(currentPosition + Binary.BigEndian.ReadInt32(codeStream), () => new Label()))); } - break; - case Opcode.TABLESWITCH: - { - while (codeStream.Position % 4 != 0) - codeStream.ReadByteFully(); - var tableSwitchInstruction = new TableSwitchInstruction - { - Default = labels.GetOrAdd(currentPosition + Binary.BigEndian.ReadInt32(codeStream), new Label()), - LowValue = Binary.BigEndian.ReadInt32(codeStream), - HighValue = Binary.BigEndian.ReadInt32(codeStream) - }; - for (var i = tableSwitchInstruction.LowValue; i <= tableSwitchInstruction.HighValue; i++) - { - tableSwitchInstruction.Labels.Add( - labels.GetOrAdd(currentPosition + Binary.BigEndian.ReadInt32(codeStream), new Label())); - } + instructions.Add(currentPosition, lookupSwitchInstruction); + } + break; - instructions.Add(currentPosition, tableSwitchInstruction); + case Opcode.TABLESWITCH: { + while (codeStream.Position % 4 != 0) + codeStream.ReadByteFully(); + TableSwitchInstruction tableSwitchInstruction = new TableSwitchInstruction { + Default = labels.GetOrAdd(currentPosition + Binary.BigEndian.ReadInt32(codeStream), () => new Label()), + LowValue = Binary.BigEndian.ReadInt32(codeStream), + HighValue = Binary.BigEndian.ReadInt32(codeStream) + }; + for (int i = tableSwitchInstruction.LowValue; i <= tableSwitchInstruction.HighValue; i++) { + tableSwitchInstruction.Labels.Add( + labels.GetOrAdd(currentPosition + Binary.BigEndian.ReadInt32(codeStream), () => new Label())); } + + instructions.Add(currentPosition, tableSwitchInstruction); + } break; case Opcode.INVOKEDYNAMIC: - var callSiteSpecifier = readerState.ConstantPool.GetEntry( - Binary.BigEndian.ReadUInt16(codeStream)); + InvokeDynamicEntry callSiteSpecifier = readerState.ConstantPool.GetEntry( + Binary.BigEndian.ReadUInt16(codeStream)); if (Binary.BigEndian.ReadUInt16(codeStream) != 0) throw new ArgumentException("INVOKEDYNAMIC 3rd and 4th bytes != 0"); - instructions.Add(currentPosition, new InvokeDynamicInstruction - { + instructions.Add(currentPosition, new InvokeDynamicInstruction { Name = callSiteSpecifier.NameAndType.Name.String, Descriptor = MethodDescriptor.Parse(callSiteSpecifier.NameAndType.Descriptor.String), BootstrapMethod = bootstrapMethodsAttribute.BootstrapMethods[callSiteSpecifier.BootstrapMethodAttributeIndex].BootstrapMethodReference, @@ -247,17 +237,14 @@ public static void ParseCodeAttribute(MethodNode parseTo, ClassReaderState reade break; case Opcode.NEWARRAY: - instructions.Add(currentPosition, new NewArrayInstruction - { + instructions.Add(currentPosition, new NewArrayInstruction { ArrayType = (NewArrayTypeCode) codeStream.ReadByteFully() }); break; case Opcode.MULTIANEWARRAY: - instructions.Add(currentPosition, new MultiANewArrayInstruction - { - Type = new ClassName(readerState.ConstantPool - .GetEntry(Binary.BigEndian.ReadUInt16(codeStream)).Name.String), + instructions.Add(currentPosition, new MultiANewArrayInstruction { + Type = new ClassName(readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(codeStream)).Name.String), Dimensions = codeStream.ReadByteFully() }); break; @@ -266,41 +253,35 @@ public static void ParseCodeAttribute(MethodNode parseTo, ClassReaderState reade case Opcode.INSTANCEOF: case Opcode.ANEWARRAY: case Opcode.NEW: - instructions.Add(currentPosition, new TypeInstruction(opcode) - { + instructions.Add(currentPosition, new TypeInstruction(opcode) { Type = new ClassName(readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(codeStream)).Name.String) }); break; case Opcode.IINC: - if (wideFlag) - { - instructions.Add(currentPosition - 1, new IncrementInstruction - { + if (wideFlag) { + instructions.Add(currentPosition - 1, new IncrementInstruction { VariableIndex = Binary.BigEndian.ReadUInt16(codeStream), Value = Binary.BigEndian.ReadInt16(codeStream) }); wideFlag = false; - } - else - { - instructions.Add(currentPosition, new IncrementInstruction - { + } + else { + instructions.Add(currentPosition, new IncrementInstruction { VariableIndex = codeStream.ReadByteFully(), - Value = codeStream.ReadByteFully() + Value = (sbyte) codeStream.ReadByteFully() }); } + break; case Opcode.BIPUSH: - instructions.Add(currentPosition, new IntegerPushInstruction(opcode) - { + instructions.Add(currentPosition, new IntegerPushInstruction(opcode) { Value = codeStream.ReadByteFully() }); break; case Opcode.SIPUSH: - instructions.Add(currentPosition, new IntegerPushInstruction(opcode) - { + instructions.Add(currentPosition, new IntegerPushInstruction(opcode) { Value = Binary.BigEndian.ReadUInt16(codeStream) }); break; @@ -317,19 +298,16 @@ public static void ParseCodeAttribute(MethodNode parseTo, ClassReaderState reade case Opcode.LSTORE: case Opcode.RET: ushort variableIndex; - if (wideFlag) - { + if (wideFlag) { variableIndex = Binary.BigEndian.ReadUInt16(codeStream); currentPosition--; wideFlag = false; - } - else - { + } + else { variableIndex = codeStream.ReadByteFully(); } - instructions.Add(currentPosition, new VariableInstruction(opcode) - { + instructions.Add(currentPosition, new VariableInstruction(opcode) { VariableIndex = variableIndex }); break; @@ -337,8 +315,7 @@ public static void ParseCodeAttribute(MethodNode parseTo, ClassReaderState reade case Opcode.ALOAD_1: case Opcode.ALOAD_2: case Opcode.ALOAD_3: - instructions.Add(currentPosition, new VariableInstruction(Opcode.ALOAD) - { + instructions.Add(currentPosition, new VariableInstruction(Opcode.ALOAD) { VariableIndex = opcode - Opcode.ALOAD_0 }); break; @@ -346,8 +323,7 @@ public static void ParseCodeAttribute(MethodNode parseTo, ClassReaderState reade case Opcode.ASTORE_1: case Opcode.ASTORE_2: case Opcode.ASTORE_3: - instructions.Add(currentPosition, new VariableInstruction(Opcode.ASTORE) - { + instructions.Add(currentPosition, new VariableInstruction(Opcode.ASTORE) { VariableIndex = opcode - Opcode.ASTORE_0 }); break; @@ -355,8 +331,7 @@ public static void ParseCodeAttribute(MethodNode parseTo, ClassReaderState reade case Opcode.DLOAD_1: case Opcode.DLOAD_2: case Opcode.DLOAD_3: - instructions.Add(currentPosition, new VariableInstruction(Opcode.DLOAD) - { + instructions.Add(currentPosition, new VariableInstruction(Opcode.DLOAD) { VariableIndex = opcode - Opcode.DLOAD_0 }); break; @@ -364,8 +339,7 @@ public static void ParseCodeAttribute(MethodNode parseTo, ClassReaderState reade case Opcode.DSTORE_1: case Opcode.DSTORE_2: case Opcode.DSTORE_3: - instructions.Add(currentPosition, new VariableInstruction(Opcode.DSTORE) - { + instructions.Add(currentPosition, new VariableInstruction(Opcode.DSTORE) { VariableIndex = opcode - Opcode.DSTORE_0 }); break; @@ -373,8 +347,7 @@ public static void ParseCodeAttribute(MethodNode parseTo, ClassReaderState reade case Opcode.FLOAD_1: case Opcode.FLOAD_2: case Opcode.FLOAD_3: - instructions.Add(currentPosition, new VariableInstruction(Opcode.FLOAD) - { + instructions.Add(currentPosition, new VariableInstruction(Opcode.FLOAD) { VariableIndex = opcode - Opcode.FLOAD_0 }); break; @@ -382,8 +355,7 @@ public static void ParseCodeAttribute(MethodNode parseTo, ClassReaderState reade case Opcode.FSTORE_1: case Opcode.FSTORE_2: case Opcode.FSTORE_3: - instructions.Add(currentPosition, new VariableInstruction(Opcode.FSTORE) - { + instructions.Add(currentPosition, new VariableInstruction(Opcode.FSTORE) { VariableIndex = opcode - Opcode.FSTORE_0 }); break; @@ -391,8 +363,7 @@ public static void ParseCodeAttribute(MethodNode parseTo, ClassReaderState reade case Opcode.ILOAD_1: case Opcode.ILOAD_2: case Opcode.ILOAD_3: - instructions.Add(currentPosition, new VariableInstruction(Opcode.ILOAD) - { + instructions.Add(currentPosition, new VariableInstruction(Opcode.ILOAD) { VariableIndex = opcode - Opcode.ILOAD_0 }); break; @@ -400,8 +371,7 @@ public static void ParseCodeAttribute(MethodNode parseTo, ClassReaderState reade case Opcode.ISTORE_1: case Opcode.ISTORE_2: case Opcode.ISTORE_3: - instructions.Add(currentPosition, new VariableInstruction(Opcode.ISTORE) - { + instructions.Add(currentPosition, new VariableInstruction(Opcode.ISTORE) { VariableIndex = opcode - Opcode.ISTORE_0 }); break; @@ -409,8 +379,7 @@ public static void ParseCodeAttribute(MethodNode parseTo, ClassReaderState reade case Opcode.LLOAD_1: case Opcode.LLOAD_2: case Opcode.LLOAD_3: - instructions.Add(currentPosition, new VariableInstruction(Opcode.LLOAD) - { + instructions.Add(currentPosition, new VariableInstruction(Opcode.LLOAD) { VariableIndex = opcode - Opcode.LLOAD_0 }); break; @@ -418,8 +387,7 @@ public static void ParseCodeAttribute(MethodNode parseTo, ClassReaderState reade case Opcode.LSTORE_1: case Opcode.LSTORE_2: case Opcode.LSTORE_3: - instructions.Add(currentPosition, new VariableInstruction(Opcode.LSTORE) - { + instructions.Add(currentPosition, new VariableInstruction(Opcode.LSTORE) { VariableIndex = opcode - Opcode.LSTORE_0 }); break; @@ -427,117 +395,122 @@ public static void ParseCodeAttribute(MethodNode parseTo, ClassReaderState reade case Opcode.INVOKEINTERFACE: case Opcode.INVOKESPECIAL: case Opcode.INVOKESTATIC: - case Opcode.INVOKEVIRTUAL: - { - MethodReferenceEntry methodReferenceEntry; - if (opcode == Opcode.INVOKEINTERFACE) - { - methodReferenceEntry = readerState.ConstantPool.GetEntry( - Binary.BigEndian.ReadUInt16(codeStream)); - var sizeOfArguments = codeStream.ReadByteFully(); - var requiredSizeOfArguments = - MethodDescriptor.Parse(methodReferenceEntry.NameAndType.Descriptor.String).ArgumentTypes.Sum(x => x.SizeOnStack) + 1; - if (sizeOfArguments != requiredSizeOfArguments) - throw new ArgumentOutOfRangeException(nameof(sizeOfArguments), $"Required size does not equal to provided: {requiredSizeOfArguments} > {sizeOfArguments}"); - if (codeStream.ReadByteFully() != 0) - throw new ArgumentException("INVOKEINTERFACE 4th byte is not 0"); - } - else - { - methodReferenceEntry = readerState.ConstantPool.GetEntry( - Binary.BigEndian.ReadUInt16(codeStream)); - } - - instructions.Add(currentPosition, new MethodInstruction(opcode) - { - Owner = new ClassName(methodReferenceEntry.Class.Name.String), - Descriptor = MethodDescriptor.Parse(methodReferenceEntry.NameAndType.Descriptor.String), - Name = methodReferenceEntry.NameAndType.Name.String - }); + case Opcode.INVOKEVIRTUAL: { + MethodReferenceEntry methodReferenceEntry; + if (opcode == Opcode.INVOKEINTERFACE) { + methodReferenceEntry = readerState.ConstantPool.GetEntry( + Binary.BigEndian.ReadUInt16(codeStream)); + byte sizeOfArguments = codeStream.ReadByteFully(); + int requiredSizeOfArguments = + MethodDescriptor.Parse(methodReferenceEntry.NameAndType.Descriptor.String).ArgumentTypes.Sum(x => x.SizeOnStack) + 1; + if (sizeOfArguments != requiredSizeOfArguments) + throw new ArgumentOutOfRangeException(nameof(sizeOfArguments), $"Required size does not equal to provided: {requiredSizeOfArguments} > {sizeOfArguments}"); + if (codeStream.ReadByteFully() != 0) + throw new ArgumentException("INVOKEINTERFACE 4th byte is not 0"); + } + else { + methodReferenceEntry = readerState.ConstantPool.GetEntry( + Binary.BigEndian.ReadUInt16(codeStream)); } + + instructions.Add(currentPosition, new MethodInstruction(opcode) { + Owner = new ClassName(methodReferenceEntry.Class.Name.String), + Descriptor = MethodDescriptor.Parse(methodReferenceEntry.NameAndType.Descriptor.String), + Name = methodReferenceEntry.NameAndType.Name.String + }); + } break; case Opcode.GETFIELD: case Opcode.GETSTATIC: case Opcode.PUTFIELD: case Opcode.PUTSTATIC: - var fieldReferenceEntry = readerState.ConstantPool.GetEntry( - Binary.BigEndian.ReadUInt16(codeStream)); - instructions.Add(currentPosition, new FieldInstruction(opcode) - { + FieldReferenceEntry fieldReferenceEntry = readerState.ConstantPool.GetEntry( + Binary.BigEndian.ReadUInt16(codeStream)); + instructions.Add(currentPosition, new FieldInstruction(opcode) { Owner = new ClassName(fieldReferenceEntry.Class.Name.String), Descriptor = TypeDescriptor.Parse(fieldReferenceEntry.NameAndType.Descriptor.String), Name = fieldReferenceEntry.NameAndType.Name.String }); break; - case Opcode.LDC: - { - var constantPoolEntry = - readerState.ConstantPool.GetEntry(codeStream.ReadByteFully()); - instructions.Add(currentPosition, new LdcInstruction - { - Value = constantPoolEntry switch - { - IntegerEntry integerEntry => integerEntry.Value, - FloatEntry floatEntry => floatEntry.Value, - StringEntry stringEntry => stringEntry.Value.String, - ClassEntry classEntry => new ClassName(classEntry.Name.String), - MethodTypeEntry methodTypeEntry => MethodDescriptor.Parse(methodTypeEntry.Descriptor.String), - MethodHandleEntry methodHandleEntry => Handle.FromConstantPool(methodHandleEntry), - _ => throw new ArgumentOutOfRangeException(nameof(constantPoolEntry), - $"Tried to {opcode} wrong type of CP entry: {constantPoolEntry.Tag}") - } - }); + case Opcode.LDC: { + Entry constantPoolEntry = readerState.ConstantPool.GetEntry(codeStream.ReadByteFully()); + + object ldcVal; + switch (constantPoolEntry) { + case IntegerEntry ie: + ldcVal = ie.Value; + break; + case FloatEntry fe: + ldcVal = fe.Value; + break; + case StringEntry se: + ldcVal = se.Value.String; + break; + case ClassEntry ce: + ldcVal = new ClassName(ce.Name.String); + break; + case MethodTypeEntry mte: + ldcVal = MethodDescriptor.Parse(mte.Descriptor.String); + break; + case MethodHandleEntry mhe: + ldcVal = Handle.FromConstantPool(mhe); + break; + default: throw new ArgumentOutOfRangeException(nameof(constantPoolEntry), $"Tried to {opcode} wrong type of CP entry: {constantPoolEntry.Tag}"); } + + instructions.Add(currentPosition, new LdcInstruction(opcode) {Value = ldcVal}); + } break; case Opcode.LDC_W: - case Opcode.LDC2_W: - { - var constantPoolEntry = - readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(codeStream)); - instructions.Add(currentPosition, new LdcInstruction - { - Value = constantPoolEntry switch - { - IntegerEntry integerEntry when opcode == Opcode.LDC_W => integerEntry.Value, - FloatEntry floatEntry when opcode == Opcode.LDC_W => floatEntry.Value, - StringEntry stringEntry when opcode == Opcode.LDC_W => stringEntry.Value.String, - ClassEntry classEntry when opcode == Opcode.LDC_W => new ClassName(classEntry.Name - .String), - MethodTypeEntry methodTypeEntry when opcode == Opcode.LDC_W => MethodDescriptor.Parse( - methodTypeEntry.Descriptor.String), - MethodHandleEntry methodHandleEntry when opcode == Opcode.LDC_W => new Handle - { - Descriptor = methodHandleEntry.ReferenceKind.IsFieldReference() - ? (IDescriptor) TypeDescriptor.Parse(methodHandleEntry.Reference.NameAndType - .Descriptor.String) - : (IDescriptor) MethodDescriptor.Parse(methodHandleEntry.Reference.NameAndType - .Descriptor.String), - Name = methodHandleEntry.Reference.NameAndType.Name.String, - Owner = new ClassName(methodHandleEntry.Reference.Class.Name.String) - }, - DoubleEntry doubleEntry when opcode == Opcode.LDC2_W => doubleEntry.Value, - LongEntry longEntry when opcode == Opcode.LDC2_W => longEntry.Value, - _ => throw new ArgumentOutOfRangeException(nameof(constantPoolEntry), - $"Tried to {opcode} wrong type of CP entry: {constantPoolEntry.GetType()}") - } - }); + case Opcode.LDC2_W: { + Entry constantPoolEntry = readerState.ConstantPool.GetEntry(Binary.BigEndian.ReadUInt16(codeStream)); + object ldcValue; + switch (constantPoolEntry) { + case IntegerEntry ie when opcode == Opcode.LDC_W: + ldcValue = ie.Value; + break; + case FloatEntry fe when opcode == Opcode.LDC_W: + ldcValue = fe.Value; + break; + case StringEntry se when opcode == Opcode.LDC_W: + ldcValue = se.Value.String; + break; + case ClassEntry ce when opcode == Opcode.LDC_W: + ldcValue = new ClassName(ce.Name.String); + break; + case MethodTypeEntry mte when opcode == Opcode.LDC_W: + ldcValue = MethodDescriptor.Parse(mte.Descriptor.String); + break; + case MethodHandleEntry mhe when opcode == Opcode.LDC_W: + ldcValue = new Handle {Descriptor = mhe.ReferenceKind.IsFieldReference() ? TypeDescriptor.Parse(mhe.Reference.NameAndType.Descriptor.String) : (IDescriptor) MethodDescriptor.Parse(mhe.Reference.NameAndType.Descriptor.String), Name = mhe.Reference.NameAndType.Name.String, Owner = new ClassName(mhe.Reference.Class.Name.String)}; + break; + case DoubleEntry de when opcode == Opcode.LDC2_W: + ldcValue = de.Value; + break; + case LongEntry le when opcode == Opcode.LDC2_W: + ldcValue = le.Value; + break; + default: throw new ArgumentOutOfRangeException(nameof(constantPoolEntry), $"Tried to {opcode} wrong type of CP entry: {constantPoolEntry.GetType()}"); } + + instructions.Add(currentPosition, new LdcInstruction { + Value = ldcValue, + Opcode = opcode + }); + } break; - case Opcode.None: - throw new ArgumentOutOfRangeException(nameof(opcode), "wut?!"); + case Opcode.None: throw new ArgumentOutOfRangeException(nameof(opcode), "wut?!"); - case Opcode.BREAKPOINT: - throw new ArgumentOutOfRangeException(nameof(opcode), $"Opcode {opcode} is currently not supported"); + case Opcode.BREAKPOINT: throw new ArgumentOutOfRangeException(nameof(opcode), $"Opcode {opcode} is currently not supported"); case Opcode.WIDE: wideFlag = true; continue; - default: - throw new ArgumentOutOfRangeException(nameof(opcode)); + default: throw new ArgumentOutOfRangeException(nameof(opcode)); } if (wideFlag) @@ -548,74 +521,96 @@ public static void ParseCodeAttribute(MethodNode parseTo, ClassReaderState reade throw new ArgumentException("Label key is not at the beginning of instruction"); parseTo.Instructions = new InstructionList(); - parseTo.TryCatches.Capacity = codeAttribute.ExceptionTable.Count; - foreach (var exceptionTableEntry in codeAttribute.ExceptionTable) - { - parseTo.TryCatches.Add(new TryCatchNode - { + foreach (CodeAttribute.ExceptionTableEntry exceptionTableEntry in codeAttribute.ExceptionTable) { + parseTo.TryCatches.Add(new TryCatchNode { ExceptionClassName = exceptionTableEntry.CatchType, - Start = labels.GetOrAdd(exceptionTableEntry.StartPc, new Label()), - End = labels.GetOrAdd(exceptionTableEntry.EndPc, new Label()), - Handler = labels.GetOrAdd(exceptionTableEntry.HandlerPc, new Label()) + Start = labels.GetOrAdd(exceptionTableEntry.StartPc, () => new Label()), + End = labels.GetOrAdd(exceptionTableEntry.EndPc, () => new Label()), + Handler = labels.GetOrAdd(exceptionTableEntry.HandlerPc, () => new Label()) }); } - var instructionList = instructions.OrderBy(x => x.Key).ToList(); - - var labelList = labels.OrderBy(x => x.Key).ToList(); - var labelListPosition = 0; - - var lineNumberTable = ((GetAttribute(codeAttribute.Attributes, PredefinedAttributeNames.LineNumberTable)?.ParsedAttribute - as LineNumberTableAttribute)?.LineNumberTable ?? new List()).OrderBy(x => x.StartPc).ToList(); + List> instructionList = instructions.OrderBy(x => x.Key).ToList(); + List> labelList = labels.OrderBy(x => x.Key).ToList(); + List lineNumberTable = ((GetAttribute(codeAttribute.Attributes, PredefinedAttributeNames.LineNumberTable)?.ParsedAttribute as LineNumberTableAttribute)?.LineNumberTable ?? new List()).OrderBy(x => x.StartPc).ToList(); if (lineNumberTable.Any(position => !instructions.ContainsKey(position.StartPc))) throw new ArgumentException("Line number is not at the beginning of instruction"); - var lineNumberTablePosition = 0; - var stackMapFrames = new List<(int Position, StackMapFrame Frame)>(); - var stackMapFramesPosition = 0; + if (parseTo.LocalVariableTable == null) { + parseTo.LocalVariableTable = new List(); + } + else { + parseTo.LocalVariableTable.Clear(); + } + + if (parseTo.LocalVariableTypeTable == null) { + parseTo.LocalVariableTypeTable = new List(); + } + else { + parseTo.LocalVariableTypeTable.Clear(); + } + + if (GetAttribute(codeAttribute.Attributes, PredefinedAttributeNames.LocalVariableTable)?.ParsedAttribute is LocalVariableTableAttribute lvt && lvt.LocalVariableTable != null) { + foreach (LocalVariableTableAttribute.LocalVariableTableEntry entry in lvt.LocalVariableTable) { + parseTo.LocalVariableTable.Add(new LocalVariableTableAttribute.LocalVariableTableEntry() { + StartPc = entry.StartPc, + Length = entry.Length, + Name = entry.Name, + Descriptor = entry.Descriptor, + Index = entry.Index + }); + } + } + + if (GetAttribute(codeAttribute.Attributes, PredefinedAttributeNames.LocalVariableTypeTable)?.ParsedAttribute is LocalVariableTypeTableAttribute lvtt && lvtt.LocalVariableTypeTable != null) { + foreach (LocalVariableTypeTableAttribute.LocalVariableTypeTableEntry entry in lvtt.LocalVariableTypeTable) { + parseTo.LocalVariableTypeTable.Add(new LocalVariableTypeTableAttribute.LocalVariableTypeTableEntry() { + Index = entry.Index, + StartPc = entry.StartPc, + Length = entry.Length, + Name = entry.Name, + Signature = entry.Signature + }); + } + } + + int labelListPosition = 0; + int lineNumberTablePosition = 0; + List<(int Position, StackMapFrame Frame)> stackMapFrames = new List<(int Position, StackMapFrame Frame)>(); + int stackMapFramesPosition = 0; { - var stackMapTable = (GetAttribute(codeAttribute.Attributes, PredefinedAttributeNames.StackMapTable)?.ParsedAttribute - as StackMapTableAttribute)?.Entries; - if (stackMapTable != null) - { + List stackMapTable = (GetAttribute(codeAttribute.Attributes, PredefinedAttributeNames.StackMapTable)?.ParsedAttribute as StackMapTableAttribute)?.Entries; + if (stackMapTable != null) { stackMapFrames.Capacity = stackMapTable.Count; - var position = 0; - var hasProcessedFirst = false; - foreach (var entry in stackMapTable) - { - VerificationElement ConvertVerificationElement(StackMapTableAttribute.VerificationElement sourceVerificationElement) - { + int position = 0; + bool hasProcessedFirst = false; + foreach (StackMapTableAttribute.StackMapFrame entry in stackMapTable) { + VerificationElement ConvertVerificationElement(StackMapTableAttribute.VerificationElement sourceVerificationElement) { VerificationElement verificationElement; - switch (sourceVerificationElement) - { + switch (sourceVerificationElement) { case StackMapTableAttribute.SimpleVerificationElement simpleVerificationElement: - verificationElement = new SimpleVerificationElement((VerificationElementType)simpleVerificationElement.Type); + verificationElement = new SimpleVerificationElement((VerificationElementType) simpleVerificationElement.Type); break; case StackMapTableAttribute.ObjectVerificationElement objectVerificationElement: - verificationElement = new ObjectVerificationElement - { + verificationElement = new ObjectVerificationElement { ObjectClass = objectVerificationElement.ObjectClass }; break; - case StackMapTableAttribute.UninitializedVerificationElement uninitializedVerificationElement: - { - var newInstruction = instructions[uninitializedVerificationElement.NewInstructionOffset]; + case StackMapTableAttribute.UninitializedVerificationElement uninitializedVerificationElement: { + Instruction newInstruction = instructions[uninitializedVerificationElement.NewInstructionOffset]; if (newInstruction.Opcode != Opcode.NEW) throw new ArgumentException( $"New instruction required by verification element is not NEW: {newInstruction.Opcode}", nameof(newInstruction)); - verificationElement = new UninitializedVerificationElement - { + verificationElement = new UninitializedVerificationElement { NewInstruction = (TypeInstruction) newInstruction }; break; } - default: - throw new ArgumentOutOfRangeException(nameof(verificationElement)); - + default: throw new ArgumentOutOfRangeException(nameof(verificationElement)); } return verificationElement; @@ -623,8 +618,7 @@ VerificationElement ConvertVerificationElement(StackMapTableAttribute.Verificati position += entry.OffsetDelta + (hasProcessedFirst ? 1 : 0); - var stackMapFrame = new StackMapFrame - { + StackMapFrame stackMapFrame = new StackMapFrame { Type = (FrameType) entry.Type, ChopK = entry.ChopK }; @@ -647,39 +641,34 @@ VerificationElement ConvertVerificationElement(StackMapTableAttribute.Verificati GetAttribute(codeAttribute.Attributes, PredefinedAttributeNames.LocalVariableTypeTable); } - foreach (var (position, instruction) in instructionList) - { + foreach (KeyValuePair pair in instructionList) { while (lineNumberTablePosition < lineNumberTable.Count && - position >= lineNumberTable[lineNumberTablePosition].StartPc) - parseTo.Instructions.Add(new LineNumber - { + pair.Key >= lineNumberTable[lineNumberTablePosition].StartPc) + parseTo.Instructions.Add(new LineNumber { Line = lineNumberTable[lineNumberTablePosition++].LineNumber }); - while (labelListPosition < labelList.Count && position >= labelList[labelListPosition].Key) + while (labelListPosition < labelList.Count && pair.Key >= labelList[labelListPosition].Key) parseTo.Instructions.Add(labelList[labelListPosition++].Value); - while (stackMapFramesPosition < stackMapFrames.Count && position >= stackMapFrames[stackMapFramesPosition].Position) + while (stackMapFramesPosition < stackMapFrames.Count && pair.Key >= stackMapFrames[stackMapFramesPosition].Position) parseTo.Instructions.Add(stackMapFrames[stackMapFramesPosition++].Frame); - parseTo.Instructions.Add(instruction); + parseTo.Instructions.Add(pair.Value); } + while (labelListPosition < labelList.Count) parseTo.Instructions.Add(labelList[labelListPosition++].Value); while (stackMapFramesPosition < stackMapFrames.Count) parseTo.Instructions.Add(stackMapFrames[stackMapFramesPosition++].Frame); } - public static CodeAttribute SaveCodeAttribute(MethodNode source, ClassWriterState writerState) - { - var codeAttribute = new CodeAttribute - { + public static CodeAttribute SaveCodeAttribute(MethodNode source, ClassWriterState writerState) { + CodeAttribute codeAttribute = new CodeAttribute { Attributes = source.CodeAttributes, MaxLocals = source.MaxLocals, MaxStack = source.MaxStack }; - foreach (var instruction in source.Instructions) - { - switch (instruction) - { + foreach (Instruction instruction in source.Instructions) { + switch (instruction) { case FieldInstruction fieldInstruction: writerState.ConstantPool.Find(new FieldReferenceEntry( new ClassEntry(new Utf8Entry(fieldInstruction.Owner.Name)), @@ -696,35 +685,52 @@ public static CodeAttribute SaveCodeAttribute(MethodNode source, ClassWriterStat writerState.ConstantPool.Find(new ClassEntry(new Utf8Entry(typeInstruction.Type.Name))); break; case LdcInstruction ldcInstruction: - writerState.ConstantPool.Find(ldcInstruction.Value switch - { - int integerValue => new IntegerEntry(integerValue), - float floatValue => new FloatEntry(floatValue), - string stringValue => new StringEntry(new Utf8Entry(stringValue)), - long longValue => new LongEntry(longValue), - double doubleValue => new DoubleEntry(doubleValue), - ClassName className => new ClassEntry(new Utf8Entry(className.Name)), - Handle handle => handle.ToConstantPool(), - MethodDescriptor methodDescriptor => new MethodTypeEntry(new Utf8Entry(methodDescriptor.ToString())), - _ => throw new ArgumentOutOfRangeException(nameof(ldcInstruction.Value), $"Can't encode value of type {ldcInstruction.Value.GetType()}") - }); + Entry entry; + switch (ldcInstruction.Value) { + case int integerValue: + entry = new IntegerEntry(integerValue); + break; + case float floatValue: + entry = new FloatEntry(floatValue); + break; + case string stringValue: + entry = new StringEntry(new Utf8Entry(stringValue)); + break; + case long longValue: + entry = new LongEntry(longValue); + break; + case double doubleValue: + entry = new DoubleEntry(doubleValue); + break; + case ClassName className: + entry = new ClassEntry(new Utf8Entry(className.Name)); + break; + case Handle handle: + entry = handle.ToConstantPool(); + break; + case MethodDescriptor methodDescriptor: + entry = new MethodTypeEntry(new Utf8Entry(methodDescriptor.ToString())); + break; + default: throw new ArgumentOutOfRangeException(nameof(ldcInstruction.Value), $"Can't encode value of type {ldcInstruction.Value.GetType()}"); + } + + writerState.ConstantPool.Find(entry); break; case MultiANewArrayInstruction multiANewArrayInstruction: writerState.ConstantPool.Find(new ClassEntry(new Utf8Entry(multiANewArrayInstruction.Type.Name))); break; case InvokeDynamicInstruction invokeDynamicInstruction: - var bootstrapMethodAttributeNode = + AttributeNode bootstrapMethodAttributeNode = writerState.ClassNode.Attributes.FirstOrDefault(x => x.Name == PredefinedAttributeNames.BootstrapMethods); if (bootstrapMethodAttributeNode == null) - writerState.ClassNode.Attributes.Add(bootstrapMethodAttributeNode = new AttributeNode - { + writerState.ClassNode.Attributes.Add(bootstrapMethodAttributeNode = new AttributeNode { Name = PredefinedAttributeNames.BootstrapMethods, ParsedAttribute = new BootstrapMethodsAttribute() }); if (!(bootstrapMethodAttributeNode.ParsedAttribute is BootstrapMethodsAttribute bootstrapMethodAttribute)) throw new Exception("BootstrapMethods attribute exists, but in not-parsed state"); - var bootstrapMethod = new BootstrapMethod(invokeDynamicInstruction.BootstrapMethod, invokeDynamicInstruction.BootstrapMethodArgs); + BootstrapMethod bootstrapMethod = new BootstrapMethod(invokeDynamicInstruction.BootstrapMethod, invokeDynamicInstruction.BootstrapMethodArgs); if (!bootstrapMethodAttribute.BootstrapMethods.Contains(bootstrapMethod)) bootstrapMethodAttribute.BootstrapMethods.Add(bootstrapMethod); writerState.ConstantPool.Find(new InvokeDynamicEntry((ushort) bootstrapMethodAttribute.BootstrapMethods.FindIndex(x => x.Equals(bootstrapMethod)), @@ -743,25 +749,30 @@ public static CodeAttribute SaveCodeAttribute(MethodNode source, ClassWriterStat case VariableInstruction _: case StackMapFrame _: break; - default: - throw new ArgumentOutOfRangeException(nameof(instruction)); + default: throw new ArgumentOutOfRangeException(nameof(instruction)); } } - var lineNumbers = new List(); - - var stackMapFrames = new List(); - var previousStackMapFramePosition = -1; - - var instructions = new Dictionary(); - - var currentPosition = 0; - foreach (var instruction in source.Instructions) - { + List lineNumbers = new List(); + List stackMapFrames = new List(); + // Dictionary>> lvtMap = new Dictionary>>(); + // LVTEntry GetLVTEForFrame(int localVariableIndex) { + // if (!lvtMap.TryGetValue(localFrameIndex, out Dictionary> dict)) { + // lvtMap[localFrameIndex] = dict = new Dictionary>(); + // } + // if (!dict.TryGetValue(localVariableIndex, out LVTEntry lvte)) { + // dict[localVariableIndex] = lvte = new LVTEntry(); + // } + // return lvte; + // } + + Dictionary instructions = new Dictionary(); + int currentPosition = 0; + int previousStackMapFramePosition = -1; + foreach (Instruction instruction in source.Instructions) { instructions.Add(instruction, (ushort) currentPosition); currentPosition += instruction.Opcode == Opcode.None ? 0 : sizeof(byte); - switch (instruction) - { + switch (instruction) { case FieldInstruction _: currentPosition += sizeof(ushort); break; @@ -772,10 +783,10 @@ public static CodeAttribute SaveCodeAttribute(MethodNode source, ClassWriterStat currentPosition += sizeof(ushort); break; case IncrementInstruction incrementInstruction: - currentPosition += incrementInstruction.VariableIndex > byte.MaxValue || + currentPosition += incrementInstruction.VariableIndex > byte.MaxValue || incrementInstruction.Value > sbyte.MaxValue || incrementInstruction.Value < sbyte.MinValue - ? sizeof(ushort) * 2 + sizeof(byte) - : sizeof(byte) * 2; + ? sizeof(ushort) * 2 + sizeof(byte) + : sizeof(byte) * 2; break; case IntegerPushInstruction integerPushInstruction: currentPosition += integerPushInstruction.Opcode == Opcode.SIPUSH @@ -786,28 +797,51 @@ public static CodeAttribute SaveCodeAttribute(MethodNode source, ClassWriterStat currentPosition += sizeof(ushort); break; case LdcInstruction ldcInstruction: - if (ldcInstruction.Value is long || ldcInstruction.Value is double) + if (ldcInstruction.Value is long || ldcInstruction.Value is double) { + currentPosition += sizeof(ushort); + } + else if (ldcInstruction.Opcode == Opcode.LDC2_W || ldcInstruction.Opcode == Opcode.LDC_W) { currentPosition += sizeof(ushort); - else - { - var constantPoolEntryIndex = ldcInstruction.Value switch - { - int integerValue => writerState.ConstantPool.Find(new IntegerEntry(integerValue)), - float floatValue => writerState.ConstantPool.Find(new FloatEntry(floatValue)), - string stringValue => writerState.ConstantPool.Find( - new StringEntry(new Utf8Entry(stringValue))), - ClassName className => writerState.ConstantPool.Find(new ClassEntry(new Utf8Entry(className.Name))), - Handle handle => writerState.ConstantPool.Find(handle.ToConstantPool()), - MethodDescriptor methodDescriptor => writerState.ConstantPool.Find(new MethodTypeEntry(new Utf8Entry(methodDescriptor.ToString()))), - _ => throw new ArgumentOutOfRangeException(nameof(ldcInstruction.Value), - $"Can't encode value of type {ldcInstruction.Value.GetType()}") - }; - currentPosition += constantPoolEntryIndex > byte.MaxValue ? sizeof(ushort) : sizeof(byte); } + else { + ushort constantPoolEntryIndex; + switch (ldcInstruction.Value) { + case int integerValue: + constantPoolEntryIndex = writerState.ConstantPool.Find(new IntegerEntry(integerValue)); + break; + case float floatValue: + constantPoolEntryIndex = writerState.ConstantPool.Find(new FloatEntry(floatValue)); + break; + case string stringValue: + constantPoolEntryIndex = writerState.ConstantPool.Find(new StringEntry(new Utf8Entry(stringValue))); + break; + case ClassName className: + constantPoolEntryIndex = writerState.ConstantPool.Find(new ClassEntry(new Utf8Entry(className.Name))); + break; + case Handle handle: + constantPoolEntryIndex = writerState.ConstantPool.Find(handle.ToConstantPool()); + break; + case MethodDescriptor methodDescriptor: + constantPoolEntryIndex = writerState.ConstantPool.Find(new MethodTypeEntry(new Utf8Entry(methodDescriptor.ToString()))); + break; + default: throw new ArgumentOutOfRangeException(nameof(ldcInstruction.Value), $"Can't encode value of type {ldcInstruction.Value.GetType()}"); + } + + // There's this too... it just has to mutate the LDC instruction, otherwise verification fails + // But then this will probably offset the LVT more so :/ + // it's probably easier to figure out a replacement for the LVT + if (constantPoolEntryIndex > byte.MaxValue) { + currentPosition += sizeof(ushort); + ldcInstruction.Opcode = Opcode.LDC_W; + } + else { + currentPosition += sizeof(byte); + } + } + break; case LineNumber lineNumber: - lineNumbers.Add(new LineNumberTableAttribute.LineNumberTableEntry - { + lineNumbers.Add(new LineNumberTableAttribute.LineNumberTableEntry { LineNumber = lineNumber.Line, StartPc = (ushort) currentPosition }); @@ -826,49 +860,43 @@ public static CodeAttribute SaveCodeAttribute(MethodNode source, ClassWriterStat case NewArrayInstruction _: currentPosition += sizeof(byte); break; - case SimpleInstruction _: - break; + case SimpleInstruction _: break; case TableSwitchInstruction tableSwitchInstruction: while (currentPosition % 4 != 0) currentPosition++; currentPosition += sizeof(int) * 3 + sizeof(int) * tableSwitchInstruction.Labels.Count; break; - case VariableInstruction variableInstruction: - if (variableInstruction.Opcode != Opcode.RET && variableInstruction.VariableIndex < 4) + case VariableInstruction varInsn: + if (varInsn.Opcode != Opcode.RET && varInsn.VariableIndex < 4) break; - currentPosition += variableInstruction.VariableIndex > byte.MaxValue - ? sizeof(ushort) + sizeof(byte) - : sizeof(byte); + + currentPosition += varInsn.VariableIndex > byte.MaxValue ? sizeof(ushort) + sizeof(byte) : sizeof(byte); + break; case InvokeDynamicInstruction _: currentPosition += sizeof(ushort) + sizeof(ushort); break; - default: - throw new ArgumentOutOfRangeException(nameof(instruction)); + default: throw new ArgumentOutOfRangeException(nameof(instruction)); } if (currentPosition > ushort.MaxValue) throw new ArgumentOutOfRangeException(nameof(currentPosition)); } - if (lineNumbers.Count > 0) - { + if (lineNumbers.Count > 0) { if (codeAttribute.Attributes.Any(x => x.Name == PredefinedAttributeNames.LineNumberTable)) throw new ArgumentException($"There is already a {PredefinedAttributeNames.LineNumberTable} attribute"); codeAttribute.Attributes.Add(new AttributeNode { Name = PredefinedAttributeNames.LineNumberTable, - ParsedAttribute = new LineNumberTableAttribute - { + ParsedAttribute = new LineNumberTableAttribute { LineNumberTable = lineNumbers } }); } codeAttribute.ExceptionTable.Capacity = source.TryCatches.Count; - foreach (var tryCatchNode in source.TryCatches) - { - codeAttribute.ExceptionTable.Add(new CodeAttribute.ExceptionTableEntry - { + foreach (TryCatchNode tryCatchNode in source.TryCatches) { + codeAttribute.ExceptionTable.Add(new CodeAttribute.ExceptionTableEntry { CatchType = tryCatchNode.ExceptionClassName, StartPc = instructions[tryCatchNode.Start], EndPc = instructions[tryCatchNode.End], @@ -876,16 +904,82 @@ public static CodeAttribute SaveCodeAttribute(MethodNode source, ClassWriterStat }); } - using var codeDataStream = new MemoryStream(currentPosition); + if (source.LocalVariableTable != null && source.LocalVariableTable.Count > 0) { + if (codeAttribute.Attributes.Any(x => x.Name == PredefinedAttributeNames.LocalVariableTable)) + throw new ArgumentException($"There is already a {PredefinedAttributeNames.LocalVariableTable} attribute"); - foreach (var instruction in source.Instructions) - { - var position = (ushort) codeDataStream.Position; + foreach (LocalVariableTableAttribute.LocalVariableTableEntry entry in source.LocalVariableTable) { + entry.StartPc = Math.Max((ushort) 0, entry.StartPc); + uint end = entry.EndPC; + if (end > currentPosition) { + entry.Length = (ushort) Math.Max(0, entry.Length - (currentPosition - (int) entry.EndPC)); + } + } - if (position != instructions[instruction]) - throw new Exception($"Wrong position: {position} != {instructions[instruction]}"); - switch (instruction) - { + codeAttribute.Attributes.Add(new AttributeNode { + Name = PredefinedAttributeNames.LocalVariableTable, + ParsedAttribute = new LocalVariableTableAttribute() { + LocalVariableTable = source.LocalVariableTable.ToList() + } + }); + } + + if (source.LocalVariableTypeTable != null && source.LocalVariableTypeTable.Count > 0) { + if (codeAttribute.Attributes.Any(x => x.Name == PredefinedAttributeNames.LocalVariableTypeTable)) + throw new ArgumentException($"There is already a {PredefinedAttributeNames.LocalVariableTypeTable} attribute"); + + foreach (LocalVariableTypeTableAttribute.LocalVariableTypeTableEntry entry in source.LocalVariableTypeTable) { + entry.StartPc = Math.Max((ushort) 0, entry.StartPc); + uint end = entry.EndPC; + if (end > currentPosition) { + entry.Length = (ushort) Math.Max(0, entry.Length - (currentPosition - (int) entry.EndPC)); + } + } + + codeAttribute.Attributes.Add(new AttributeNode { + Name = PredefinedAttributeNames.LocalVariableTypeTable, + ParsedAttribute = new LocalVariableTypeTableAttribute() { + LocalVariableTypeTable = source.LocalVariableTypeTable.ToList() + } + }); + } + + MemoryStream codeDataStream = new MemoryStream(currentPosition); + + Dictionary actualInstructions = new Dictionary(); + Instruction prevInstruction = null; + foreach (Instruction instruction in source.Instructions) { + ushort position = (ushort) codeDataStream.Position; + actualInstructions[instruction] = position; + + if (position != instructions[instruction]) { + StringBuilder sb = new StringBuilder(); + sb.AppendLine($"Verification error while writing instructions for {source}"); + sb.AppendLine($"Wrong position: {position} != {instructions[instruction]}"); + if (prevInstruction != null) { + sb.AppendLine($" Previous instruction: {prevInstruction.GetType()} -> {prevInstruction}"); + } + + if (prevInstruction != null) { + sb.AppendLine($" Current instruction: {instruction.GetType()} -> {instruction}"); + } + + sb.AppendLine($" Verification Instruction map:"); + foreach (KeyValuePair entry in instructions) { + sb.AppendLine($" {entry.Key.GetType().Name} ({entry.Key}) at position {entry.Value}"); + } + + sb.AppendLine($" Actual Instruction map:"); + foreach (KeyValuePair entry in actualInstructions) { + sb.AppendLine($" {entry.Key.GetType().Name} ({entry.Key}) at position {entry.Value}"); + } + + throw new Exception(sb.ToString()); + } + + prevInstruction = instruction; + + switch (instruction) { case FieldInstruction fieldInstruction: codeDataStream.WriteByte((byte) fieldInstruction.Opcode); Binary.BigEndian.Write(codeDataStream, writerState.ConstantPool.Find(new FieldReferenceEntry( @@ -895,25 +989,24 @@ public static CodeAttribute SaveCodeAttribute(MethodNode source, ClassWriterStat break; case MethodInstruction methodInstruction: codeDataStream.WriteByte((byte) methodInstruction.Opcode); - if (methodInstruction.Opcode == Opcode.INVOKEINTERFACE) - { + if (methodInstruction.Opcode == Opcode.INVOKEINTERFACE) { Binary.BigEndian.Write(codeDataStream, writerState.ConstantPool.Find(new InterfaceMethodReferenceEntry( new ClassEntry(new Utf8Entry(methodInstruction.Owner.Name)), new NameAndTypeEntry(new Utf8Entry(methodInstruction.Name), new Utf8Entry(methodInstruction.Descriptor.ToString()))))); if (methodInstruction.Descriptor.ArgumentTypes.Sum(x => x.SizeOnStack) + 1 > byte.MaxValue) - throw new ArgumentOutOfRangeException(nameof(methodInstruction.Descriptor.ArgumentTypes.Count), + throw new ArgumentOutOfRangeException(nameof(methodInstruction.Descriptor.ArgumentTypes.Count), $"Too many arguments: {methodInstruction.Descriptor.ArgumentTypes.Sum(x => x.SizeOnStack) + 1} > {byte.MaxValue}"); codeDataStream.WriteByte((byte) (methodInstruction.Descriptor.ArgumentTypes.Sum(x => x.SizeOnStack) + 1)); codeDataStream.WriteByte(0); - } - else - { + } + else { Binary.BigEndian.Write(codeDataStream, writerState.ConstantPool.Find(new MethodReferenceEntry( new ClassEntry(new Utf8Entry(methodInstruction.Owner.Name)), new NameAndTypeEntry(new Utf8Entry(methodInstruction.Name), new Utf8Entry(methodInstruction.Descriptor.ToString()))))); } + break; case TypeInstruction typeInstruction: codeDataStream.WriteByte((byte) typeInstruction.Opcode); @@ -925,16 +1018,15 @@ public static CodeAttribute SaveCodeAttribute(MethodNode source, ClassWriterStat codeDataStream.WriteByte((byte) Opcode.WIDE); codeDataStream.WriteByte((byte) incrementInstruction.Opcode); if (incrementInstruction.VariableIndex > byte.MaxValue || - incrementInstruction.Value > sbyte.MaxValue || incrementInstruction.Value < sbyte.MinValue) - { + incrementInstruction.Value > sbyte.MaxValue || incrementInstruction.Value < sbyte.MinValue) { Binary.BigEndian.Write(codeDataStream, incrementInstruction.VariableIndex); Binary.BigEndian.Write(codeDataStream, incrementInstruction.Value); } - else - { + else { codeDataStream.WriteByte((byte) incrementInstruction.VariableIndex); codeDataStream.WriteByte(unchecked((byte) incrementInstruction.Value)); } + break; case IntegerPushInstruction integerPushInstruction: codeDataStream.WriteByte((byte) integerPushInstruction.Opcode); @@ -948,33 +1040,81 @@ public static CodeAttribute SaveCodeAttribute(MethodNode source, ClassWriterStat Binary.BigEndian.Write(codeDataStream, (short) (instructions[jumpInstruction.Target] - instructions[jumpInstruction])); break; case LdcInstruction ldcInstruction: - var constantPoolEntryIndex = ldcInstruction.Value switch - { - int integerValue => writerState.ConstantPool.Find(new IntegerEntry(integerValue)), - float floatValue => writerState.ConstantPool.Find(new FloatEntry(floatValue)), - string stringValue => writerState.ConstantPool.Find( - new StringEntry(new Utf8Entry(stringValue))), - long longValue => writerState.ConstantPool.Find(new LongEntry(longValue)), - double doubleValue => writerState.ConstantPool.Find(new DoubleEntry(doubleValue)), - ClassName className => writerState.ConstantPool.Find(new ClassEntry(new Utf8Entry(className.Name))), - Handle handle => writerState.ConstantPool.Find(handle.ToConstantPool()), - MethodDescriptor methodDescriptor => writerState.ConstantPool.Find(new MethodTypeEntry(new Utf8Entry(methodDescriptor.ToString()))), - _ => throw new ArgumentOutOfRangeException(nameof(ldcInstruction.Value), - $"Can't encode value of type {ldcInstruction.Value.GetType()}") - }; - if (ldcInstruction.Value is long || ldcInstruction.Value is double) - { + ushort constantPoolEntryIndex; + switch (ldcInstruction.Value) { + case int integerValue: + constantPoolEntryIndex = writerState.ConstantPool.Find(new IntegerEntry(integerValue)); + break; + case float floatValue: + constantPoolEntryIndex = writerState.ConstantPool.Find(new FloatEntry(floatValue)); + break; + case string stringValue: + constantPoolEntryIndex = writerState.ConstantPool.Find(new StringEntry(new Utf8Entry(stringValue))); + break; + case long longValue: + constantPoolEntryIndex = writerState.ConstantPool.Find(new LongEntry(longValue)); + break; + case double doubleValue: + constantPoolEntryIndex = writerState.ConstantPool.Find(new DoubleEntry(doubleValue)); + break; + case ClassName className: + constantPoolEntryIndex = writerState.ConstantPool.Find(new ClassEntry(new Utf8Entry(className.Name))); + break; + case Handle handle: + constantPoolEntryIndex = writerState.ConstantPool.Find(handle.ToConstantPool()); + break; + case MethodDescriptor methodDescriptor: + constantPoolEntryIndex = writerState.ConstantPool.Find(new MethodTypeEntry(new Utf8Entry(methodDescriptor.ToString()))); + break; + default: throw new ArgumentOutOfRangeException(nameof(ldcInstruction.Value), $"Can't encode value of type {ldcInstruction.Value.GetType()}"); + } + + if (ldcInstruction.Value is long || ldcInstruction.Value is double) { + if (ldcInstruction.Opcode == Opcode.LDC) { + throw new InvalidOperationException($"LDC value is a long/double, but it's op-code is not LDC2_W ({ldcInstruction.Opcode}). Value: " + ldcInstruction.Value); + } + codeDataStream.WriteByte((byte) Opcode.LDC2_W); Binary.BigEndian.Write(codeDataStream, constantPoolEntryIndex); } - else - { - codeDataStream.WriteByte((byte) (constantPoolEntryIndex > byte.MaxValue ? Opcode.LDC_W : Opcode.LDC)); - if (constantPoolEntryIndex > byte.MaxValue) + else { + // TODO: What to do here? + // If the original const pool index was, for example, below or equal to 255, but the new + // index is is above 255, LDC_W will be required and therefore may lead to the LVT (local variable table) being offset + // Overall problem: The LVT may contain an entry whose length is near or at the end of the code + // Therefore, if LDC_W is converted to LDC, then the LVT length is past the size of the bytecode, + // which can cause errors in in asm libraries and possibly in classloading (usually array index out of bounds) + + // Old code: + // codeDataStream.WriteByte((byte) ((constantPoolEntryIndex > byte.MaxValue) ? Opcode.LDC_W : Opcode.LDC)); + // New code: + // write the instruction's original opcode only if wide is not required + // the original opcode may be wide anyway. To clarify, this is to prefent an original LDC_W being + // converted to LDC, possilby causing the LVT being offset + // The way the LVT is stored could be modified in this library, so it's not actually a table/map, + // but is actually stored in the instructions themselves maybe? not sure... but the way it is, + // seems very fiddily to actually fix this problem + + + bool isWideRequired = (byte) constantPoolEntryIndex > byte.MaxValue; + if (isWideRequired || ldcInstruction.Opcode != Opcode.LDC) { + // LDC2_W is only used for long/double... afaik + codeDataStream.WriteByte((byte) Opcode.LDC_W); Binary.BigEndian.Write(codeDataStream, constantPoolEntryIndex); - else + } + // else if (isWideRequired) { + // // throwing an exception seems bad, because the user has no + // // control over the precise constant pool index + // codeDataStream.WriteByte((byte) Opcode.LDC_W); + // Binary.BigEndian.Write(codeDataStream, constantPoolEntryIndex); + // } + else { + // should always be LDC + codeDataStream.WriteByte((byte) ldcInstruction.Opcode); codeDataStream.WriteByte((byte) constantPoolEntryIndex); + } } + break; case LookupSwitchInstruction lookupSwitchInstruction: codeDataStream.WriteByte((byte) lookupSwitchInstruction.Opcode); @@ -982,11 +1122,11 @@ public static CodeAttribute SaveCodeAttribute(MethodNode source, ClassWriterStat codeDataStream.WriteByte(0); Binary.BigEndian.Write(codeDataStream, instructions[lookupSwitchInstruction.Default] - position); Binary.BigEndian.Write(codeDataStream, lookupSwitchInstruction.MatchLabels.Count); - foreach (var (key, label) in lookupSwitchInstruction.MatchLabels) - { - Binary.BigEndian.Write(codeDataStream, key); - Binary.BigEndian.Write(codeDataStream, instructions[label] - position); + foreach (KeyValuePair pair in lookupSwitchInstruction.MatchLabels) { + Binary.BigEndian.Write(codeDataStream, pair.Key); + Binary.BigEndian.Write(codeDataStream, instructions[pair.Value] - position); } + break; case MultiANewArrayInstruction multiANewArrayInstruction: codeDataStream.WriteByte((byte) multiANewArrayInstruction.Opcode); @@ -1010,15 +1150,13 @@ public static CodeAttribute SaveCodeAttribute(MethodNode source, ClassWriterStat if (tableSwitchInstruction.HighValue - tableSwitchInstruction.LowValue + 1 != tableSwitchInstruction.Labels.Count) throw new ArgumentOutOfRangeException(nameof(tableSwitchInstruction)); - foreach (var label in tableSwitchInstruction.Labels) + foreach (Label label in tableSwitchInstruction.Labels) Binary.BigEndian.Write(codeDataStream, instructions[label] - position); break; case VariableInstruction variableInstruction: - if (variableInstruction.Opcode != Opcode.RET && variableInstruction.VariableIndex < 4) - { + if (variableInstruction.Opcode != Opcode.RET && variableInstruction.VariableIndex < 4) { // ReSharper disable once SwitchStatementMissingSomeCases - switch (variableInstruction.Opcode) - { + switch (variableInstruction.Opcode) { case Opcode.ASTORE: codeDataStream.WriteByte((byte) ((byte) Opcode.ASTORE_0 + variableInstruction.VariableIndex)); break; @@ -1049,12 +1187,10 @@ public static CodeAttribute SaveCodeAttribute(MethodNode source, ClassWriterStat case Opcode.LLOAD: codeDataStream.WriteByte((byte) ((byte) Opcode.LLOAD_0 + variableInstruction.VariableIndex)); break; - default: - throw new ArgumentOutOfRangeException(nameof(variableInstruction.Opcode)); + default: throw new ArgumentOutOfRangeException(nameof(variableInstruction.Opcode)); } } - else - { + else { if (variableInstruction.VariableIndex > byte.MaxValue) codeDataStream.WriteByte((byte) Opcode.WIDE); codeDataStream.WriteByte((byte) variableInstruction.Opcode); @@ -1063,98 +1199,87 @@ public static CodeAttribute SaveCodeAttribute(MethodNode source, ClassWriterStat else codeDataStream.WriteByte((byte) variableInstruction.VariableIndex); } + break; case InvokeDynamicInstruction invokeDynamicInstruction: codeDataStream.WriteByte((byte) invokeDynamicInstruction.Opcode); - var bootstrapMethodAttribute = + BootstrapMethodsAttribute bootstrapMethodAttribute = writerState.ClassNode.Attributes.FirstOrDefault(x => x.Name == PredefinedAttributeNames.BootstrapMethods).ParsedAttribute as BootstrapMethodsAttribute; - var bootstrapMethod = new BootstrapMethod(invokeDynamicInstruction.BootstrapMethod, invokeDynamicInstruction.BootstrapMethodArgs); + BootstrapMethod bootstrapMethod = new BootstrapMethod(invokeDynamicInstruction.BootstrapMethod, invokeDynamicInstruction.BootstrapMethodArgs); Binary.BigEndian.Write(codeDataStream, writerState.ConstantPool.Find(new InvokeDynamicEntry( - (ushort) bootstrapMethodAttribute.BootstrapMethods.FindIndex(x => x.Equals(bootstrapMethod)), - new NameAndTypeEntry(new Utf8Entry(invokeDynamicInstruction.Name), - new Utf8Entry(invokeDynamicInstruction.Descriptor.ToString()))))); + (ushort) bootstrapMethodAttribute.BootstrapMethods.FindIndex(x => x.Equals(bootstrapMethod)), + new NameAndTypeEntry(new Utf8Entry(invokeDynamicInstruction.Name), + new Utf8Entry(invokeDynamicInstruction.Descriptor.ToString()))))); Binary.BigEndian.Write(codeDataStream, (ushort) 0); break; case StackMapFrame stackMapFrame: - StackMapTableAttribute.VerificationElement ConvertVerificationElement( - VerificationElement sourceVerificationElement) - { + StackMapTableAttribute.VerificationElement ConvertVerificationElement(VerificationElement sourceVerificationElement) { StackMapTableAttribute.VerificationElement verificationElement; - switch (sourceVerificationElement) - { + switch (sourceVerificationElement) { case ObjectVerificationElement objectVerificationElement: - verificationElement = new StackMapTableAttribute.ObjectVerificationElement - { + verificationElement = new StackMapTableAttribute.ObjectVerificationElement { ObjectClass = objectVerificationElement.ObjectClass }; break; case SimpleVerificationElement simpleVerificationElement: verificationElement = new StackMapTableAttribute.SimpleVerificationElement( - (StackMapTableAttribute.VerificationElementType) simpleVerificationElement.Type); + (StackMapTableAttribute.VerificationElementType) simpleVerificationElement.Type); break; case UninitializedVerificationElement uninitializedVerificationElement: if (uninitializedVerificationElement.NewInstruction.Opcode != Opcode.NEW) throw new ArgumentOutOfRangeException(nameof(uninitializedVerificationElement.NewInstruction), $"New instruction is not NEW: {uninitializedVerificationElement.NewInstruction.Opcode}"); - verificationElement = new StackMapTableAttribute.UninitializedVerificationElement - { + verificationElement = new StackMapTableAttribute.UninitializedVerificationElement { NewInstructionOffset = instructions[uninitializedVerificationElement.NewInstruction] }; break; - default: - throw new ArgumentOutOfRangeException(nameof(sourceVerificationElement)); + default: throw new ArgumentOutOfRangeException(nameof(sourceVerificationElement)); } + return verificationElement; } StackMapTableAttribute.StackMapFrame stackMapTableEntry; - switch (stackMapFrame.Type) - { + switch (stackMapFrame.Type) { case FrameType.Same: - stackMapTableEntry = new StackMapTableAttribute.StackMapFrame - { + stackMapTableEntry = new StackMapTableAttribute.StackMapFrame { Type = StackMapTableAttribute.FrameType.Same }; break; case FrameType.SameLocals1StackItem: - stackMapTableEntry = new StackMapTableAttribute.StackMapFrame - { + stackMapTableEntry = new StackMapTableAttribute.StackMapFrame { Type = StackMapTableAttribute.FrameType.SameLocals1StackItem }; stackMapTableEntry.Stack.Add(ConvertVerificationElement(stackMapFrame.Stack[0])); break; case FrameType.Chop: - stackMapTableEntry = new StackMapTableAttribute.StackMapFrame - { + stackMapTableEntry = new StackMapTableAttribute.StackMapFrame { Type = StackMapTableAttribute.FrameType.Chop, ChopK = stackMapFrame.ChopK }; break; case FrameType.Append: - stackMapTableEntry = new StackMapTableAttribute.StackMapFrame - { + stackMapTableEntry = new StackMapTableAttribute.StackMapFrame { Type = StackMapTableAttribute.FrameType.Append }; stackMapTableEntry.Locals.AddRange(stackMapFrame.Locals.Select(ConvertVerificationElement)); break; case FrameType.Full: - stackMapTableEntry = new StackMapTableAttribute.StackMapFrame - { + stackMapTableEntry = new StackMapTableAttribute.StackMapFrame { Type = StackMapTableAttribute.FrameType.Full }; stackMapTableEntry.Locals.AddRange(stackMapFrame.Locals.Select(ConvertVerificationElement)); stackMapTableEntry.Stack.AddRange(stackMapFrame.Stack.Select(ConvertVerificationElement)); break; - default: - throw new ArgumentOutOfRangeException(nameof(stackMapFrame.Type)); + default: throw new ArgumentOutOfRangeException(nameof(stackMapFrame.Type)); } if (position - previousStackMapFramePosition <= 0) - throw new ArgumentOutOfRangeException(nameof(position), $"Wrong position delta: {position - previousStackMapFramePosition} <= 0"); + throw new ArgumentOutOfRangeException(nameof(position), $"Wrong stack frame position delta: position({position}) - previousStackMapFramePosition({previousStackMapFramePosition}) ({position - previousStackMapFramePosition}) <= 0"); stackMapTableEntry.OffsetDelta = (ushort) (position - previousStackMapFramePosition - 1); stackMapFrames.Add(stackMapTableEntry); @@ -1163,20 +1288,16 @@ StackMapTableAttribute.VerificationElement ConvertVerificationElement( case LineNumber _: case Label _: break; - default: - throw new ArgumentOutOfRangeException(nameof(instruction)); + default: throw new ArgumentOutOfRangeException(nameof(instruction)); } } - if (stackMapFrames.Count > 0) - { + if (stackMapFrames.Count > 0) { if (codeAttribute.Attributes.Any(x => x.Name == PredefinedAttributeNames.StackMapTable)) throw new ArgumentException($"There is already a {PredefinedAttributeNames.StackMapTable} attribute"); - codeAttribute.Attributes.Add(new AttributeNode - { + codeAttribute.Attributes.Add(new AttributeNode { Name = PredefinedAttributeNames.StackMapTable, - ParsedAttribute = new StackMapTableAttribute - { + ParsedAttribute = new StackMapTableAttribute { Entries = stackMapFrames } }); @@ -1187,4 +1308,4 @@ StackMapTableAttribute.VerificationElement ConvertVerificationElement( return codeAttribute; } } -} +} \ No newline at end of file diff --git a/JavaAsm/Instructions/Opcode.cs b/JavaAsm/Instructions/Opcode.cs index 040f9cd..5771e8c 100644 --- a/JavaAsm/Instructions/Opcode.cs +++ b/JavaAsm/Instructions/Opcode.cs @@ -1,10 +1,8 @@ using System.Diagnostics.CodeAnalysis; -namespace JavaAsm.Instructions -{ +namespace JavaAsm.Instructions { [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum Opcode : byte - { + public enum Opcode : byte { None = 0xFF, AALOAD = 0x32, @@ -211,4 +209,4 @@ public enum Opcode : byte TABLESWITCH = 0xAA, WIDE = 0xC4 } -} +} \ No newline at end of file diff --git a/JavaAsm/Instructions/Types/FieldInstruction.cs b/JavaAsm/Instructions/Types/FieldInstruction.cs index 02116b6..6ca2bb1 100644 --- a/JavaAsm/Instructions/Types/FieldInstruction.cs +++ b/JavaAsm/Instructions/Types/FieldInstruction.cs @@ -1,10 +1,21 @@ using JavaAsm.Helpers; -namespace JavaAsm.Instructions.Types -{ - public class FieldInstruction : Instruction - { - public override Opcode Opcode { get; } +namespace JavaAsm.Instructions.Types { + public class FieldInstruction : Instruction { + private Opcode opcode; + + public override Opcode Opcode { + get => this.opcode; + set => this.opcode = value.VerifyOpcode(nameof(value), Opcode.GETFIELD, Opcode.GETSTATIC, Opcode.PUTFIELD, Opcode.PUTSTATIC); + } + + public override Instruction Copy() { + return new FieldInstruction(this.opcode) { + Owner = this.Owner, + Name = this.Name, + Descriptor = this.Descriptor.CopyTypeDescriptor() + }; + } public ClassName Owner { get; set; } @@ -12,16 +23,12 @@ public class FieldInstruction : Instruction public TypeDescriptor Descriptor { get; set; } - public FieldInstruction(Opcode opcode) - { - opcode.CheckInAndThrow(nameof(opcode), Opcode.GETFIELD, Opcode.GETSTATIC, Opcode.PUTFIELD, - Opcode.PUTSTATIC); - Opcode = opcode; + public FieldInstruction(Opcode opcode) { + this.Opcode = opcode; } - public override string ToString() - { - return $"{Opcode} {Owner}.{Name} {Descriptor}"; + public override string ToString() { + return $"{this.Opcode} {this.Owner}.{this.Name} {this.Descriptor}"; } } -} +} \ No newline at end of file diff --git a/JavaAsm/Instructions/Types/IncrementInstruction.cs b/JavaAsm/Instructions/Types/IncrementInstruction.cs index 5e04293..469f3ae 100644 --- a/JavaAsm/Instructions/Types/IncrementInstruction.cs +++ b/JavaAsm/Instructions/Types/IncrementInstruction.cs @@ -1,16 +1,25 @@ -namespace JavaAsm.Instructions.Types -{ - public class IncrementInstruction : Instruction - { - public override Opcode Opcode => Opcode.IINC; +using System; + +namespace JavaAsm.Instructions.Types { + public class IncrementInstruction : Instruction { + public override Opcode Opcode { + get => Opcode.IINC; + set => throw new InvalidOperationException(GetType().Name + " only has 1 opcode"); + } + + public override Instruction Copy() { + return new IncrementInstruction() { + VariableIndex = this.VariableIndex, + Value = this.Value + }; + } public ushort VariableIndex { get; set; } - public short Value { get; set; } + public short Value { get; set; } - public override string ToString() - { - return $"{Opcode} {VariableIndex} {Value}"; + public override string ToString() { + return $"{this.Opcode} {this.VariableIndex} {this.Value}"; } } -} +} \ No newline at end of file diff --git a/JavaAsm/Instructions/Types/IntegerPushInstruction.cs b/JavaAsm/Instructions/Types/IntegerPushInstruction.cs index 27e369d..95a3e35 100644 --- a/JavaAsm/Instructions/Types/IntegerPushInstruction.cs +++ b/JavaAsm/Instructions/Types/IntegerPushInstruction.cs @@ -1,22 +1,28 @@ using JavaAsm.Helpers; -namespace JavaAsm.Instructions.Types -{ - public class IntegerPushInstruction : Instruction - { - public override Opcode Opcode { get; } +namespace JavaAsm.Instructions.Types { + public class IntegerPushInstruction : Instruction { + private Opcode opcode; + + public override Opcode Opcode { + get => this.opcode; + set => this.opcode = value.VerifyOpcode(nameof(value), Opcode.BIPUSH, Opcode.SIPUSH); + } + + public override Instruction Copy() { + return new IntegerPushInstruction(this.opcode) { + Value = this.Value + }; + } public ushort Value { get; set; } - public IntegerPushInstruction(Opcode opcode) - { - opcode.CheckInAndThrow(nameof(opcode), Opcode.BIPUSH, Opcode.SIPUSH); - Opcode = opcode; + public IntegerPushInstruction(Opcode opcode) { + this.Opcode = opcode; } - public override string ToString() - { - return $"{Opcode} {Value}"; + public override string ToString() { + return $"{this.Opcode} {this.Value}"; } } -} +} \ No newline at end of file diff --git a/JavaAsm/Instructions/Types/InvokeDynamicInstruction.cs b/JavaAsm/Instructions/Types/InvokeDynamicInstruction.cs index 4e99327..a9dd8dc 100644 --- a/JavaAsm/Instructions/Types/InvokeDynamicInstruction.cs +++ b/JavaAsm/Instructions/Types/InvokeDynamicInstruction.cs @@ -3,11 +3,21 @@ using JavaAsm.Helpers; using JavaAsm.IO.ConstantPoolEntries; -namespace JavaAsm.Instructions.Types -{ - public class InvokeDynamicInstruction : Instruction - { - public override Opcode Opcode => Opcode.INVOKEDYNAMIC; +namespace JavaAsm.Instructions.Types { + public class InvokeDynamicInstruction : Instruction { + public override Opcode Opcode { + get => Opcode.INVOKEDYNAMIC; + set => throw new InvalidOperationException(GetType().Name + " only has 1 instruction"); + } + + public override Instruction Copy() { + return new InvokeDynamicInstruction() { + Name = this.Name, + Descriptor = this.Descriptor.CopyMethodDescriptor(), + BootstrapMethod = this.BootstrapMethod.Copy(), + BootstrapMethodArgs = new List(this.BootstrapMethodArgs) + }; + } public string Name { get; set; } @@ -18,8 +28,7 @@ public class InvokeDynamicInstruction : Instruction public List BootstrapMethodArgs { get; set; } } - public enum ReferenceKindType : byte - { + public enum ReferenceKindType : byte { GetField = 1, GetStatic, PutField, @@ -31,8 +40,7 @@ public enum ReferenceKindType : byte InvokeReference } - public class Handle - { + public class Handle { public ReferenceKindType Type { get; set; } public ClassName Owner { get; set; } @@ -41,41 +49,52 @@ public class Handle public IDescriptor Descriptor { get; set; } - internal static Handle FromConstantPool(MethodHandleEntry methodHandleEntry) - { - return new Handle - { + internal static Handle FromConstantPool(MethodHandleEntry methodHandleEntry) { + return new Handle { Type = methodHandleEntry.ReferenceKind, Descriptor = methodHandleEntry.ReferenceKind.IsFieldReference() - ? TypeDescriptor.Parse(methodHandleEntry.Reference.NameAndType - .Descriptor.String) - : (IDescriptor) MethodDescriptor.Parse(methodHandleEntry.Reference.NameAndType - .Descriptor.String), + ? TypeDescriptor.Parse(methodHandleEntry.Reference.NameAndType.Descriptor.String) + : (IDescriptor) MethodDescriptor.Parse(methodHandleEntry.Reference.NameAndType.Descriptor.String), Name = methodHandleEntry.Reference.NameAndType.Name.String, Owner = new ClassName(methodHandleEntry.Reference.Class.Name.String) }; } - internal MethodHandleEntry ToConstantPool() - { - var referenceOwner = new ClassEntry(new Utf8Entry(Owner.Name)); - var referenceNameAndType = new NameAndTypeEntry(new Utf8Entry(Name), new Utf8Entry(Descriptor.ToString())); - var reference = Type switch - { - ReferenceKindType.GetField => (ReferenceEntry) new FieldReferenceEntry(referenceOwner, - referenceNameAndType), - ReferenceKindType.GetStatic => new FieldReferenceEntry(referenceOwner, referenceNameAndType), - ReferenceKindType.PutField => new FieldReferenceEntry(referenceOwner, referenceNameAndType), - ReferenceKindType.PutStatic => new FieldReferenceEntry(referenceOwner, referenceNameAndType), - ReferenceKindType.InvokeVirtual => new MethodReferenceEntry(referenceOwner, referenceNameAndType), - ReferenceKindType.NewInvokeSpecial => new MethodReferenceEntry(referenceOwner, referenceNameAndType), - ReferenceKindType.InvokeStatic => new MethodReferenceEntry(referenceOwner, referenceNameAndType), - ReferenceKindType.InvokeSpecial => new MethodReferenceEntry(referenceOwner, referenceNameAndType), - ReferenceKindType.InvokeReference => new InterfaceMethodReferenceEntry(referenceOwner, - referenceNameAndType), - _ => throw new ArgumentOutOfRangeException(nameof(Type)) + internal MethodHandleEntry ToConstantPool() { + ClassEntry referenceOwner = new ClassEntry(new Utf8Entry(this.Owner.Name)); + NameAndTypeEntry referenceNameAndType = new NameAndTypeEntry(new Utf8Entry(this.Name), new Utf8Entry(this.Descriptor.ToString())); + ReferenceEntry reference; + switch (this.Type) { + case ReferenceKindType.GetField: + reference = new FieldReferenceEntry(referenceOwner, referenceNameAndType); + break; + case ReferenceKindType.GetStatic: + case ReferenceKindType.PutField: + case ReferenceKindType.PutStatic: + reference = new FieldReferenceEntry(referenceOwner, referenceNameAndType); + break; + case ReferenceKindType.InvokeVirtual: + case ReferenceKindType.NewInvokeSpecial: + case ReferenceKindType.InvokeStatic: + case ReferenceKindType.InvokeSpecial: + reference = new MethodReferenceEntry(referenceOwner, referenceNameAndType); + break; + case ReferenceKindType.InvokeReference: + reference = new InterfaceMethodReferenceEntry(referenceOwner, referenceNameAndType); + break; + default: throw new ArgumentOutOfRangeException(nameof(this.Type)); + } + + return new MethodHandleEntry(this.Type, reference); + } + + public Handle Copy() { + return new Handle() { + Descriptor = this.Descriptor.Copy(), + Name = this.Name, + Owner = this.Owner != null ? new ClassName(this.Owner.Name) : null, + Type = this.Type }; - return new MethodHandleEntry(Type, reference); } } -} +} \ No newline at end of file diff --git a/JavaAsm/Instructions/Types/JumpInstruction.cs b/JavaAsm/Instructions/Types/JumpInstruction.cs index bbb766a..d2eeae4 100644 --- a/JavaAsm/Instructions/Types/JumpInstruction.cs +++ b/JavaAsm/Instructions/Types/JumpInstruction.cs @@ -1,24 +1,35 @@ using JavaAsm.Helpers; -namespace JavaAsm.Instructions.Types -{ - public class JumpInstruction : Instruction - { - public override Opcode Opcode { get; } +namespace JavaAsm.Instructions.Types { + public class JumpInstruction : Instruction { + private Opcode opcode; + + public override Opcode Opcode { + get => this.opcode; + set => this.opcode = value.VerifyOpcode(nameof(value), + Opcode.IFEQ, Opcode.IFNE, Opcode.IFLT, Opcode.IFGE, Opcode.IFGT, Opcode.IFLE, + Opcode.IF_ICMPEQ, Opcode.IF_ICMPNE, Opcode.IF_ICMPLT, Opcode.IF_ICMPGE, + Opcode.IF_ICMPGT, Opcode.IF_ICMPLE, Opcode.IF_ACMPEQ, Opcode.IF_ACMPNE, + Opcode.GOTO, Opcode.JSR, Opcode.IFNULL, Opcode.IFNONNULL); + } + + public override Instruction Copy() { + return new JumpInstruction(this.opcode) { + JumpOffset = this.JumpOffset, + Target = this.Target, + }; + } public Label Target { get; set; } - - public JumpInstruction(Opcode opcode) - { - opcode.CheckInAndThrow(nameof(opcode), Opcode.IFEQ, Opcode.IFNE, Opcode.IFLT, Opcode.IFGE, Opcode.IFGT, - Opcode.IFLE, Opcode.IF_ICMPEQ, Opcode.IF_ICMPNE, Opcode.IF_ICMPLT, Opcode.IF_ICMPGE, Opcode.IF_ICMPGT, - Opcode.IF_ICMPLE, Opcode.IF_ACMPEQ, Opcode.IF_ACMPNE, Opcode.GOTO, Opcode.JSR, Opcode.IFNULL, Opcode.IFNONNULL); - Opcode = opcode; + + public int JumpOffset { get; set; } + + public JumpInstruction(Opcode opcode) { + this.Opcode = opcode; } - public override string ToString() - { - return $"{Opcode} L{Target.Index}"; + public override string ToString() { + return $"{this.Opcode} L{(this.Target == null ? "[No target]" : this.Target.Index.ToString())}"; } } -} +} \ No newline at end of file diff --git a/JavaAsm/Instructions/Types/Label.cs b/JavaAsm/Instructions/Types/Label.cs index a3b0f3a..edaf294 100644 --- a/JavaAsm/Instructions/Types/Label.cs +++ b/JavaAsm/Instructions/Types/Label.cs @@ -1,21 +1,31 @@ -namespace JavaAsm.Instructions.Types -{ - public class Label : Instruction - { - private static long globalLabelIndex; +using System; - public long Index { get; } +namespace JavaAsm.Instructions.Types { + public class Label : Instruction { + public static long GlobalLabelIndex { get; set; } - public override Opcode Opcode => Opcode.None; + /// + /// A readable index. Modifying this has no purpose, but it can be useful for visualizing labels + /// + public long Index { get; set; } - public Label() - { - Index = globalLabelIndex++; + public override Opcode Opcode { + get => Opcode.None; + set => throw new InvalidOperationException(GetType().Name + " does not have an instruction"); } - public override string ToString() - { - return $"LABEL L{Index}"; + public override Instruction Copy() { + return new Label() { + Index = this.Index + }; + } + + public Label() { + this.Index = GlobalLabelIndex++; + } + + public override string ToString() { + return $"LABEL L{this.Index}"; } } -} +} \ No newline at end of file diff --git a/JavaAsm/Instructions/Types/LdcInstruction.cs b/JavaAsm/Instructions/Types/LdcInstruction.cs index e288bd4..5777282 100644 --- a/JavaAsm/Instructions/Types/LdcInstruction.cs +++ b/JavaAsm/Instructions/Types/LdcInstruction.cs @@ -1,17 +1,70 @@ -namespace JavaAsm.Instructions.Types -{ - public class LdcInstruction : Instruction - { - public override Opcode Opcode => Opcode.LDC; +using System; +using JavaAsm.Helpers; + +namespace JavaAsm.Instructions.Types { + public class LdcInstruction : Instruction { + private Opcode opcode; + + public override Opcode Opcode { + get => this.opcode; + set => this.opcode = value.VerifyOpcode(nameof(value), Opcode.LDC, Opcode.LDC_W, Opcode.LDC2_W); + } + + public override Instruction Copy() { + return new LdcInstruction() { + Opcode = this.opcode, + Value = CloneObject(this.Value) + }; + } + + private static object CloneObject(object value) { + if (value == null) { + return null; + } + else if (value is int) { + return (int) value; + } + else if (value is long) { + return (long) value; + } + else if (value is float) { + return (float) value; + } + else if (value is double) { + return (double) value; + } + else if (value is string) { + return (string) value; + } + else if (value is ClassName) { + return ((ClassName) value).Copy(); + } + else if (value is Handle) { + return ((Handle) value).Copy(); + } + else if (value is MethodDescriptor) { + return ((MethodDescriptor) value).CopyMethodDescriptor(); + } + else { + throw new ArgumentException($"Unknown object type: {value.GetType().Name} -> {value}"); + } + } public object Value { get; set; } - public override string ToString() - { - var stringValue = Value.ToString(); - if (Value is string) + public LdcInstruction() { + this.Opcode = Opcode.LDC; + } + + public LdcInstruction(Opcode opcode) { + this.Opcode = opcode; + } + + public override string ToString() { + string stringValue = this.Value.ToString(); + if (this.Value is string) stringValue = $"\"{stringValue}\""; - return $"{Opcode} {stringValue}"; + return $"{this.Opcode} {stringValue}"; } } -} +} \ No newline at end of file diff --git a/JavaAsm/Instructions/Types/LineNumber.cs b/JavaAsm/Instructions/Types/LineNumber.cs index f466e18..803c797 100644 --- a/JavaAsm/Instructions/Types/LineNumber.cs +++ b/JavaAsm/Instructions/Types/LineNumber.cs @@ -1,14 +1,22 @@ -namespace JavaAsm.Instructions.Types -{ - public class LineNumber : Instruction - { - public override Opcode Opcode => Opcode.None; +using System; + +namespace JavaAsm.Instructions.Types { + public class LineNumber : Instruction { + public override Opcode Opcode { + get => Opcode.None; + set => throw new InvalidOperationException(GetType().Name + " does not have an instruction"); + } + + public override Instruction Copy() { + return new LineNumber() { + Line = this.Line + }; + } public ushort Line { get; set; } - public override string ToString() - { - return $"LINE {Line}"; + public override string ToString() { + return $"LINE {this.Line}"; } } -} +} \ No newline at end of file diff --git a/JavaAsm/Instructions/Types/LookupSwitchInstruction.cs b/JavaAsm/Instructions/Types/LookupSwitchInstruction.cs index f86b8f1..e8e055c 100644 --- a/JavaAsm/Instructions/Types/LookupSwitchInstruction.cs +++ b/JavaAsm/Instructions/Types/LookupSwitchInstruction.cs @@ -1,13 +1,23 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; -namespace JavaAsm.Instructions.Types -{ - public class LookupSwitchInstruction : Instruction - { - public override Opcode Opcode => Opcode.LOOKUPSWITCH; +namespace JavaAsm.Instructions.Types { + public class LookupSwitchInstruction : Instruction { + public override Opcode Opcode { + get => Opcode.LOOKUPSWITCH; + set => throw new InvalidOperationException(GetType().Name + " only has 1 instruction"); + } + + public override Instruction Copy() { + return new LookupSwitchInstruction() { + Default = this.Default, + MatchLabels = new List>(this.MatchLabels.Select(a => new KeyValuePair(a.Key, a.Value))) + }; + } public Label Default { get; set; } public List> MatchLabels { get; set; } = new List>(); } -} +} \ No newline at end of file diff --git a/JavaAsm/Instructions/Types/MethodInstruction.cs b/JavaAsm/Instructions/Types/MethodInstruction.cs index e5cacf4..fad60ab 100644 --- a/JavaAsm/Instructions/Types/MethodInstruction.cs +++ b/JavaAsm/Instructions/Types/MethodInstruction.cs @@ -1,10 +1,21 @@ using JavaAsm.Helpers; -namespace JavaAsm.Instructions.Types -{ - public class MethodInstruction : Instruction - { - public override Opcode Opcode { get; } +namespace JavaAsm.Instructions.Types { + public class MethodInstruction : Instruction { + private Opcode opcode; + + public override Opcode Opcode { + get => this.opcode; + set => this.opcode = value.VerifyOpcode(nameof(value), Opcode.INVOKESTATIC, Opcode.INVOKEVIRTUAL, Opcode.INVOKEINTERFACE, Opcode.INVOKESPECIAL); + } + + public override Instruction Copy() { + return new MethodInstruction(this.opcode) { + Owner = this.Owner, + Name = this.Name, + Descriptor = this.Descriptor.CopyMethodDescriptor() + }; + } public ClassName Owner { get; set; } @@ -12,15 +23,12 @@ public class MethodInstruction : Instruction public MethodDescriptor Descriptor { get; set; } - public MethodInstruction(Opcode opcode) - { - opcode.CheckInAndThrow(nameof(opcode), Opcode.INVOKESTATIC, Opcode.INVOKEVIRTUAL, Opcode.INVOKEINTERFACE, - Opcode.INVOKESPECIAL); - Opcode = opcode; + public MethodInstruction(Opcode opcode) { + this.Opcode = opcode; } - public override string ToString() - { - return $"{Opcode} {Owner}.{Name}{Descriptor}"; + + public override string ToString() { + return $"{this.Opcode} {this.Owner}.{this.Name}{this.Descriptor}"; } } } \ No newline at end of file diff --git a/JavaAsm/Instructions/Types/MultiANewArrayInstruction.cs b/JavaAsm/Instructions/Types/MultiANewArrayInstruction.cs index 11ada67..5b7a593 100644 --- a/JavaAsm/Instructions/Types/MultiANewArrayInstruction.cs +++ b/JavaAsm/Instructions/Types/MultiANewArrayInstruction.cs @@ -1,16 +1,25 @@ -namespace JavaAsm.Instructions.Types -{ - public class MultiANewArrayInstruction : Instruction - { - public override Opcode Opcode => Opcode.MULTIANEWARRAY; +using System; + +namespace JavaAsm.Instructions.Types { + public class MultiANewArrayInstruction : Instruction { + public override Opcode Opcode { + get => Opcode.MULTIANEWARRAY; + set => throw new InvalidOperationException(GetType().Name + " only has 1 instruction"); + } + + public override Instruction Copy() { + return new MultiANewArrayInstruction() { + Type = this.Type.Copy(), + Dimensions = this.Dimensions + }; + } public ClassName Type { get; set; } public byte Dimensions { get; set; } - public override string ToString() - { - return $"{Opcode} {Type} {Dimensions}"; + public override string ToString() { + return $"{this.Opcode} {this.Type} {this.Dimensions}"; } } -} +} \ No newline at end of file diff --git a/JavaAsm/Instructions/Types/NewArrayInstruction.cs b/JavaAsm/Instructions/Types/NewArrayInstruction.cs index fa72d0c..a700345 100644 --- a/JavaAsm/Instructions/Types/NewArrayInstruction.cs +++ b/JavaAsm/Instructions/Types/NewArrayInstruction.cs @@ -1,19 +1,26 @@ -namespace JavaAsm.Instructions.Types -{ - public class NewArrayInstruction : Instruction - { - public override Opcode Opcode => Opcode.NEWARRAY; +using System; + +namespace JavaAsm.Instructions.Types { + public class NewArrayInstruction : Instruction { + public override Opcode Opcode { + get => Opcode.NEWARRAY; + set => throw new InvalidOperationException(GetType().Name + " only has 1 instruction"); + } + + public override Instruction Copy() { + return new NewArrayInstruction() { + ArrayType = this.ArrayType + }; + } public NewArrayTypeCode ArrayType { get; set; } - public override string ToString() - { - return $"{Opcode} {ArrayType}"; + public override string ToString() { + return $"{this.Opcode} {this.ArrayType}"; } } - public enum NewArrayTypeCode : byte - { + public enum NewArrayTypeCode : byte { Boolean = 4, Character, Float, @@ -23,4 +30,4 @@ public enum NewArrayTypeCode : byte Integer, Long } -} +} \ No newline at end of file diff --git a/JavaAsm/Instructions/Types/SimpleInstruction.cs b/JavaAsm/Instructions/Types/SimpleInstruction.cs index 193420a..40e2ce6 100644 --- a/JavaAsm/Instructions/Types/SimpleInstruction.cs +++ b/JavaAsm/Instructions/Types/SimpleInstruction.cs @@ -1,35 +1,42 @@ using JavaAsm.Helpers; -namespace JavaAsm.Instructions.Types -{ - public class SimpleInstruction : Instruction - { - public override Opcode Opcode { get; } +namespace JavaAsm.Instructions.Types { + public class SimpleInstruction : Instruction { + private static readonly Opcode[] ValidOpcodes = { + Opcode.NOP, Opcode.ACONST_NULL, Opcode.ICONST_M1, Opcode.ICONST_0, Opcode.ICONST_1, Opcode.ICONST_2, + Opcode.ICONST_3, Opcode.ICONST_4, Opcode.ICONST_5, Opcode.LCONST_0, Opcode.LCONST_1, Opcode.FCONST_0, + Opcode.FCONST_1, Opcode.FCONST_2, Opcode.DCONST_0, Opcode.DCONST_1, Opcode.IALOAD, Opcode.LALOAD, Opcode.FALOAD, + Opcode.DALOAD, Opcode.AALOAD, Opcode.BALOAD, Opcode.CALOAD, Opcode.SALOAD, Opcode.IASTORE, Opcode.LASTORE, + Opcode.FASTORE, Opcode.DASTORE, Opcode.AASTORE, Opcode.BASTORE, Opcode.CASTORE, Opcode.SASTORE, Opcode.POP, + Opcode.POP2, Opcode.DUP, Opcode.DUP_X1, Opcode.DUP_X2, Opcode.DUP2, Opcode.DUP2_X1, Opcode.DUP2_X2, Opcode.SWAP, + Opcode.IADD, Opcode.LADD, Opcode.FADD, Opcode.DADD, Opcode.ISUB, Opcode.LSUB, Opcode.FSUB, Opcode.DSUB, + Opcode.IMUL, Opcode.LMUL, Opcode.FMUL, Opcode.DMUL, Opcode.IDIV, Opcode.LDIV, Opcode.FDIV, Opcode.DDIV, + Opcode.IREM, Opcode.LREM, Opcode.FREM, Opcode.DREM, Opcode.INEG, Opcode.LNEG, Opcode.FNEG, Opcode.DNEG, + Opcode.ISHL, Opcode.LSHL, Opcode.ISHR, Opcode.LSHR, Opcode.IUSHR, Opcode.LUSHR, Opcode.IAND, Opcode.LAND, + Opcode.IOR, Opcode.LOR, Opcode.IXOR, Opcode.LXOR, Opcode.I2L, Opcode.I2F, Opcode.I2D, Opcode.L2I, Opcode.L2F, + Opcode.L2D, Opcode.F2I, Opcode.F2L, Opcode.F2D, Opcode.D2I, Opcode.D2L, Opcode.D2F, Opcode.I2B, Opcode.I2C, + Opcode.I2S, Opcode.LCMP, Opcode.FCMPL, Opcode.FCMPG, Opcode.DCMPL, Opcode.DCMPG, Opcode.IRETURN, Opcode.LRETURN, + Opcode.FRETURN, Opcode.DRETURN, Opcode.ARETURN, Opcode.RETURN, Opcode.ARRAYLENGTH, Opcode.ATHROW, + Opcode.MONITORENTER, Opcode.MONITOREXIT + }; - public SimpleInstruction(Opcode opcode) - { - opcode.CheckInAndThrow(nameof(opcode), - Opcode.NOP, Opcode.ACONST_NULL, Opcode.ICONST_M1, Opcode.ICONST_0, Opcode.ICONST_1, Opcode.ICONST_2, - Opcode.ICONST_3, Opcode.ICONST_4, Opcode.ICONST_5, Opcode.LCONST_0, Opcode.LCONST_1, Opcode.FCONST_0, - Opcode.FCONST_1, Opcode.FCONST_2, Opcode.DCONST_0, Opcode.DCONST_1, Opcode.IALOAD, Opcode.LALOAD, Opcode.FALOAD, - Opcode.DALOAD, Opcode.AALOAD, Opcode.BALOAD, Opcode.CALOAD, Opcode.SALOAD, Opcode.IASTORE, Opcode.LASTORE, - Opcode.FASTORE, Opcode.DASTORE, Opcode.AASTORE, Opcode.BASTORE, Opcode.CASTORE, Opcode.SASTORE, Opcode.POP, - Opcode.POP2, Opcode.DUP, Opcode.DUP_X1, Opcode.DUP_X2, Opcode.DUP2, Opcode.DUP2_X1, Opcode.DUP2_X2, Opcode.SWAP, - Opcode.IADD, Opcode.LADD, Opcode.FADD, Opcode.DADD, Opcode.ISUB, Opcode.LSUB, Opcode.FSUB, Opcode.DSUB, - Opcode.IMUL, Opcode.LMUL, Opcode.FMUL, Opcode.DMUL, Opcode.IDIV, Opcode.LDIV, Opcode.FDIV, Opcode.DDIV, - Opcode.IREM, Opcode.LREM, Opcode.FREM, Opcode.DREM, Opcode.INEG, Opcode.LNEG, Opcode.FNEG, Opcode.DNEG, - Opcode.ISHL, Opcode.LSHL, Opcode.ISHR, Opcode.LSHR, Opcode.IUSHR, Opcode.LUSHR, Opcode.IAND, Opcode.LAND, - Opcode.IOR, Opcode.LOR, Opcode.IXOR, Opcode.LXOR, Opcode.I2L, Opcode.I2F, Opcode.I2D, Opcode.L2I, Opcode.L2F, - Opcode.L2D, Opcode.F2I, Opcode.F2L, Opcode.F2D, Opcode.D2I, Opcode.D2L, Opcode.D2F, Opcode.I2B, Opcode.I2C, - Opcode.I2S, Opcode.LCMP, Opcode.FCMPL, Opcode.FCMPG, Opcode.DCMPL, Opcode.DCMPG, Opcode.IRETURN, Opcode.LRETURN, - Opcode.FRETURN, Opcode.DRETURN, Opcode.ARETURN, Opcode.RETURN, Opcode.ARRAYLENGTH, Opcode.ATHROW, - Opcode.MONITORENTER, Opcode.MONITOREXIT); - Opcode = opcode; + private Opcode opcode; + + public override Opcode Opcode { + get => this.opcode; + set => this.opcode = value.VerifyOpcode(nameof(value), ValidOpcodes); + } + + public override Instruction Copy() { + return new SimpleInstruction(this.opcode); + } + + public SimpleInstruction(Opcode opcode) { + this.Opcode = opcode; } - public override string ToString() - { - return $"{Opcode}"; + public override string ToString() { + return $"{this.Opcode}"; } } -} +} \ No newline at end of file diff --git a/JavaAsm/Instructions/Types/StackMapFrame.cs b/JavaAsm/Instructions/Types/StackMapFrame.cs index 337472d..6f0238c 100644 --- a/JavaAsm/Instructions/Types/StackMapFrame.cs +++ b/JavaAsm/Instructions/Types/StackMapFrame.cs @@ -1,10 +1,10 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; using JavaAsm.Helpers; -namespace JavaAsm.Instructions.Types -{ - public enum VerificationElementType - { +namespace JavaAsm.Instructions.Types { + public enum VerificationElementType { Top, Integer, Float, @@ -16,39 +16,48 @@ public enum VerificationElementType Unitialized } - public abstract class VerificationElement - { + public abstract class VerificationElement { public abstract VerificationElementType Type { get; } + + public abstract VerificationElement Copy(); } - public class SimpleVerificationElement : VerificationElement - { + public class SimpleVerificationElement : VerificationElement { public override VerificationElementType Type { get; } + public override VerificationElement Copy() { + return new SimpleVerificationElement(this.Type); + } - public SimpleVerificationElement(VerificationElementType type) - { + public SimpleVerificationElement(VerificationElementType type) { type.CheckInAndThrow(nameof(type), VerificationElementType.Top, VerificationElementType.Integer, VerificationElementType.Float, VerificationElementType.Long, VerificationElementType.Double, VerificationElementType.Null, VerificationElementType.UnitializedThis); - Type = type; + this.Type = type; } } - public class ObjectVerificationElement : VerificationElement - { + public class ObjectVerificationElement : VerificationElement { public override VerificationElementType Type => VerificationElementType.Object; + public override VerificationElement Copy() { + return new ObjectVerificationElement() { + ObjectClass = this.ObjectClass?.Copy() + }; + } public ClassName ObjectClass { get; set; } } - public class UninitializedVerificationElement : VerificationElement - { + public class UninitializedVerificationElement : VerificationElement { public override VerificationElementType Type => VerificationElementType.Unitialized; + public override VerificationElement Copy() { + return new UninitializedVerificationElement() { + NewInstruction = (TypeInstruction) this.NewInstruction?.Copy() + }; + } public TypeInstruction NewInstruction { get; set; } } - public enum FrameType - { + public enum FrameType { Same, SameLocals1StackItem, Chop, @@ -56,9 +65,21 @@ public enum FrameType Full } - public class StackMapFrame : Instruction - { - public override Opcode Opcode => Opcode.None; + public class StackMapFrame : Instruction { + public override Opcode Opcode { + get => Opcode.None; + set => throw new InvalidOperationException(GetType().Name + " does not have an instruction"); + } + + public override Instruction Copy() { + StackMapFrame insn = new StackMapFrame() { + ChopK = this.ChopK + }; + + insn.Stack.AddRange(this.Stack.Select(a => a.Copy()).ToList()); + insn.Locals.AddRange(this.Stack.Select(a => a.Copy()).ToList()); + return insn; + } public FrameType Type { get; set; } @@ -68,9 +89,8 @@ public class StackMapFrame : Instruction public byte? ChopK { get; set; } - public override string ToString() - { + public override string ToString() { return "STACKFRAME"; } } -} +} \ No newline at end of file diff --git a/JavaAsm/Instructions/Types/TableSwitchInstruction.cs b/JavaAsm/Instructions/Types/TableSwitchInstruction.cs index 1cf4ac8..1864452 100644 --- a/JavaAsm/Instructions/Types/TableSwitchInstruction.cs +++ b/JavaAsm/Instructions/Types/TableSwitchInstruction.cs @@ -1,10 +1,21 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; -namespace JavaAsm.Instructions.Types -{ - public class TableSwitchInstruction : Instruction - { - public override Opcode Opcode => Opcode.TABLESWITCH; +namespace JavaAsm.Instructions.Types { + public class TableSwitchInstruction : Instruction { + public override Opcode Opcode { + get => Opcode.TABLESWITCH; + set => throw new InvalidOperationException(GetType().Name + " only has 1 opcode"); + } + + public override Instruction Copy() { + return new TableSwitchInstruction() { + Default = this.Default, + LowValue = this.LowValue, + HighValue = this.HighValue, + Labels = new List