diff --git a/src/Class.zig b/src/Class.zig index a8719b9..58c02d1 100644 --- a/src/Class.zig +++ b/src/Class.zig @@ -12,7 +12,7 @@ allocator: std.mem.Allocator, magic: u32, minor_version: u16, major_version: u16, -constant_pool: []?ConstantPool.Info, +constant_pool: ConstantPool, access_flags: ClassAccessFlags, this_class: u16, super_class: u16, @@ -54,13 +54,8 @@ pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) (ParseError || const minor_version = try input.takeInt(u16, .big); const major_version = try input.takeInt(u16, .big); - const constant_pool = try parseConstantPool(input, allocator); - errdefer { - for (constant_pool) |*cp_info| { - if (cp_info.*) |*c| c.deinit(allocator); - } - allocator.free(constant_pool); - } + var constant_pool: ConstantPool = try .parse(input, allocator); + errdefer constant_pool.deinit(allocator); const access_flags: ClassAccessFlags = .{ .mask = try input.takeInt(u16, .big) }; @@ -110,30 +105,6 @@ pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) (ParseError || }; } -fn parseConstantPool(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError![]?ConstantPool.Info { - const constant_pool_size = try input.takeInt(u16, .big); - const constant_pool = try allocator.alloc(?ConstantPool.Info, constant_pool_size - 1); - errdefer allocator.free(constant_pool); - - var i: usize = 0; - while (i < constant_pool_size - 1) { - defer i += 1; - - const cp_info = try ConstantPool.Info.parse(input, allocator); - constant_pool[i] = cp_info; - - switch (cp_info) { - .long, .double => { - i += 1; - constant_pool[i] = null; - }, - else => {}, - } - } - - return constant_pool; -} - fn parseInterfaces(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError![]u16 { const interfaces_count = try input.takeInt(u16, .big); const interfaces = try allocator.alloc(u16, interfaces_count); @@ -146,7 +117,7 @@ fn parseInterfaces(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseErr return interfaces; } -fn parseFields(input: *std.Io.Reader, constant_pool: []const ?ConstantPool.Info, allocator: std.mem.Allocator) (ParseError || ResolveError)![]FieldInfo { +fn parseFields(input: *std.Io.Reader, constant_pool: ConstantPool, allocator: std.mem.Allocator) (ParseError || ResolveError)![]FieldInfo { const fields_count = try input.takeInt(u16, .big); const fields = try allocator.alloc(FieldInfo, fields_count); errdefer allocator.free(fields); @@ -158,19 +129,19 @@ fn parseFields(input: *std.Io.Reader, constant_pool: []const ?ConstantPool.Info, return fields; } -fn parseMethods(input: *std.Io.Reader, constant_pool: []const ?ConstantPool.Info, allocator: std.mem.Allocator) (ParseError || ResolveError)![]MethodInfo { +fn parseMethods(input: *std.Io.Reader, constant_pool: ConstantPool, allocator: std.mem.Allocator) (ParseError || ResolveError)![]MethodInfo { const methods_count = try input.takeInt(u16, .big); const methods = try allocator.alloc(MethodInfo, methods_count); errdefer allocator.free(methods); for (0..methods_count) |i| { - methods[i] = try MethodInfo.parse(input, constant_pool, allocator); + methods[i] = try .parse(input, constant_pool, allocator); } return methods; } -pub fn parseAttributes(input: *std.Io.Reader, constant_pool: []const ?ConstantPool.Info, allocator: std.mem.Allocator) (ParseError || ResolveError)![]AttributeInfo { +pub fn parseAttributes(input: *std.Io.Reader, constant_pool: ConstantPool, allocator: std.mem.Allocator) (ParseError || ResolveError)![]AttributeInfo { const attributes_count = try input.takeInt(u16, .big); const attributes = try allocator.alloc(AttributeInfo, attributes_count); errdefer allocator.free(attributes); @@ -183,20 +154,13 @@ pub fn parseAttributes(input: *std.Io.Reader, constant_pool: []const ?ConstantPo } pub fn deinit(self: *Self) void { - self.freeConstantPool(); + self.constant_pool.deinit(self.allocator); self.freeInterfaces(); self.freeFields(); self.freeMethods(); self.freeAttributes(); } -fn freeConstantPool(self: *Self) void { - for (self.constant_pool) |*cp_info| { - if (cp_info.*) |*c| c.deinit(self.allocator); - } - self.allocator.free(self.constant_pool); -} - fn freeInterfaces(self: *Self) void { self.allocator.free(self.interfaces); } @@ -258,13 +222,11 @@ pub fn format(self: *const Self, w: *std.Io.Writer) std.Io.Writer.Error!void { indent += 1; defer indent -= 1; - if (interface >= self.constant_pool.len) return error.WriteFailed; - const cp_info = self.constant_pool[interface - 1]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return error.WriteFailed; + const info = self.constant_pool.getTag(interface, .class) catch return error.WriteFailed; try w.splatByteAll(' ', depth * indent); try w.print("{d}:\n", .{ i }); - try cp_info.?.indentedFormat(w, depth, indent + 1, self.constant_pool); + try info.indentedFormat(w, depth, indent + 1, self.constant_pool); } _ = try w.write("fields:\n"); @@ -299,11 +261,7 @@ pub fn format(self: *const Self, w: *std.Io.Writer) std.Io.Writer.Error!void { } pub fn thisClass(self: *const Self) ResolveError!ConstantPool.Info { - const this_class = self.this_class - 1; - if (this_class >= self.constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = self.constant_pool[this_class]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; - return cp_info.?; + return self.constant_pool.getTag(self.this_class, .class); } pub fn superClass(self: *const Self) ResolveError!?ConstantPool.Info { @@ -313,17 +271,14 @@ pub fn superClass(self: *const Self) ResolveError!?ConstantPool.Info { if (!std.mem.eql(u8, this_class_name.bytes, "java/lang/Object")) return ResolveError.InvalidConstantType; return null; } else { - const super_class = self.super_class - 1; - if (super_class >= self.constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = self.constant_pool[super_class]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; + const super_class = try self.constant_pool.getTag(self.super_class, .class); if (self.access_flags.contains(.interface)) { - const super_class_name = (try cp_info.?.class.name(self.constant_pool)).utf8; + const super_class_name = (try super_class.class.name(self.constant_pool)).utf8; if (!std.mem.eql(u8, super_class_name.bytes, "java/lang/Object")) return ResolveError.InvalidConstantType; } else { // TODO: Assert that superclass does not have ACC_FINAL flag set. } - return cp_info.?; + return super_class; } } diff --git a/src/Class/AttributeInfo.zig b/src/Class/AttributeInfo.zig index ec44f51..0e9540d 100644 --- a/src/Class/AttributeInfo.zig +++ b/src/Class/AttributeInfo.zig @@ -44,12 +44,10 @@ pub const AttributeInfo = union(enum) { const Self = @This(); - pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPool.Info, allocator: std.mem.Allocator) (ParseError || ResolveError)!AttributeInfo { - const attribute_name_index = try input.takeInt(u16, .big) - 1; - if (attribute_name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[attribute_name_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - const attribute_name = cp_info.?.utf8; + pub fn parse(input: *std.Io.Reader, constant_pool: ConstantPool, allocator: std.mem.Allocator) (ParseError || ResolveError)!AttributeInfo { + const attribute_name_index = try input.takeInt(u16, .big); + const attribute_name = try constant_pool.getTag(attribute_name_index, .utf8); + const name = attribute_name.utf8.bytes; const attribute_length = try input.takeInt(u32, .big); @@ -57,169 +55,169 @@ pub const AttributeInfo = union(enum) { var limited_reader: std.Io.Reader.Limited = .init(input, .limited(attribute_length), &limited_buf); const limited = &limited_reader.interface; - if (std.mem.eql(u8, attribute_name.bytes, "ConstantValue")) { + if (std.mem.eql(u8, name, "ConstantValue")) { return .{ .predefined = .{ .constant_value = try ConstantValue.parse(limited), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "Code")) { + } else if (std.mem.eql(u8, name, "Code")) { return .{ .predefined = .{ .code = try Code.parse(limited, constant_pool, allocator), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "StackMapTable")) { + } else if (std.mem.eql(u8, name, "StackMapTable")) { return .{ .predefined = .{ .stack_map_table = try StackMapTable.parse(limited, allocator), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "Exceptions")) { + } else if (std.mem.eql(u8, name, "Exceptions")) { return .{ .predefined = .{ .exceptions = try Exceptions.parse(limited, allocator), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "InnerClasses")) { + } else if (std.mem.eql(u8, name, "InnerClasses")) { return .{ .predefined = .{ .inner_classes = try InnerClasses.parse(limited, allocator), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "EnclosingMethod")) { + } else if (std.mem.eql(u8, name, "EnclosingMethod")) { return .{ .predefined = .{ .enclosing_method = try EnclosingMethod.parse(limited), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "Synthetic")) { + } else if (std.mem.eql(u8, name, "Synthetic")) { return .{ .predefined = .{ .synthetic = .{}, }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "Signature")) { + } else if (std.mem.eql(u8, name, "Signature")) { return .{ .predefined = .{ .signature = try Signature.parse(limited), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "SourceFile")) { + } else if (std.mem.eql(u8, name, "SourceFile")) { return .{ .predefined = .{ .source_file = try SourceFile.parse(limited), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "SourceDebugExtension")) { + } else if (std.mem.eql(u8, name, "SourceDebugExtension")) { return .{ .predefined = .{ .source_debug_extension = try SourceDebugExtension.parse(limited, attribute_length, allocator), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "LineNumberTable")) { + } else if (std.mem.eql(u8, name, "LineNumberTable")) { return .{ .predefined = .{ .line_number_table = try LineNumberTable.parse(limited, allocator), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "LocalVariableTable")) { + } else if (std.mem.eql(u8, name, "LocalVariableTable")) { return .{ .predefined = .{ .local_variable_table = try LocalVariableTable.parse(limited, allocator), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "LocalVariableTypeTable")) { + } else if (std.mem.eql(u8, name, "LocalVariableTypeTable")) { return .{ .predefined = .{ .local_variable_type_table = try LocalVariableTypeTable.parse(limited, allocator), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "Deprecated")) { + } else if (std.mem.eql(u8, name, "Deprecated")) { return .{ .predefined = .{ .deprecated = .{}, }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "RuntimeVisibleAnnotations")) { + } else if (std.mem.eql(u8, name, "RuntimeVisibleAnnotations")) { return .{ .predefined = .{ .runtime_visible_annotations = try RuntimeVisibleAnnotations.parse(limited, allocator), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "RuntimeInvisibleAnnotations")) { + } else if (std.mem.eql(u8, name, "RuntimeInvisibleAnnotations")) { return .{ .predefined = .{ .runtime_invisible_annotations = try RuntimeInvisibleAnnotations.parse(limited, allocator), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "RuntimeVisibleParameterAnnotations")) { + } else if (std.mem.eql(u8, name, "RuntimeVisibleParameterAnnotations")) { return .{ .predefined = .{ .runtime_visible_parameter_annotations = try RuntimeVisibleParameterAnnotations.parse(limited, allocator), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "RuntimeInvisibleParameterAnnotations")) { + } else if (std.mem.eql(u8, name, "RuntimeInvisibleParameterAnnotations")) { return .{ .predefined = .{ .runtime_invisible_parameter_annotations = try RuntimeInvisibleParameterAnnotations.parse(limited, allocator), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "AnnotationDefault")) { + } else if (std.mem.eql(u8, name, "AnnotationDefault")) { return .{ .predefined = .{ .annotation_default = try AnnotationDefault.parse(limited, allocator), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "BootstrapMethods")) { + } else if (std.mem.eql(u8, name, "BootstrapMethods")) { return .{ .predefined = .{ .bootstrap_methods = try BootstrapMethods.parse(limited, allocator), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "MethodParameters")) { + } else if (std.mem.eql(u8, name, "MethodParameters")) { return .{ .predefined = .{ .method_parameters = try MethodParameters.parse(limited, allocator), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "Module")) { + } else if (std.mem.eql(u8, name, "Module")) { return .{ .predefined = .{ .module = try Module.parse(limited, allocator), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "ModulePackages")) { + } else if (std.mem.eql(u8, name, "ModulePackages")) { return .{ .predefined = .{ .module_packages = try ModulePackages.parse(limited, allocator), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "ModuleMainClass")) { + } else if (std.mem.eql(u8, name, "ModuleMainClass")) { return .{ .predefined = .{ .module_main_class = try ModuleMainClass.parse(limited), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "NestHost")) { + } else if (std.mem.eql(u8, name, "NestHost")) { return .{ .predefined = .{ .nest_host = try NestHost.parse(limited), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "NestMembers")) { + } else if (std.mem.eql(u8, name, "NestMembers")) { return .{ .predefined = .{ .nest_members = try NestMembers.parse(limited, allocator), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "Record")) { + } else if (std.mem.eql(u8, name, "Record")) { return .{ .predefined = .{ .record = try Record.parse(limited, constant_pool, allocator), }, }; - } else if (std.mem.eql(u8, attribute_name.bytes, "PermittedSubclasses")) { + } else if (std.mem.eql(u8, name, "PermittedSubclasses")) { return .{ .predefined = .{ .permitted_subclasses = try PermittedSubclasses.parse(limited, allocator), @@ -266,7 +264,7 @@ pub const AttributeInfo = union(enum) { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPool.Info, + constant_pool: ConstantPool, ) std.Io.Writer.Error!void { switch (self.*) { .new => |new| { @@ -343,15 +341,11 @@ pub const AttributeInfo = union(enum) { exception_indent += 1; defer exception_indent -= 1; - const index = exception_index - 1; - - if (index >= constant_pool.len) return error.WriteFailed; - const cp_info = constant_pool[index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return error.WriteFailed; + const info = constant_pool.getTag(exception_index, .class) catch return error.WriteFailed; try w.splatByteAll(' ', depth * exception_indent); try w.print("{d}:\n", .{ i }); - try cp_info.?.indentedFormat(w, depth, exception_indent + 1, constant_pool); + try info.indentedFormat(w, depth, exception_indent + 1, constant_pool); } }, .inner_classes => |attr| { @@ -482,15 +476,11 @@ pub const AttributeInfo = union(enum) { package_indent += 1; defer package_indent -= 1; - const index = package_index - 1; - - if (index >= constant_pool.len) return error.WriteFailed; - const cp_info = constant_pool[index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .package) return error.WriteFailed; + const info = constant_pool.getTag(package_index, .package) catch return error.WriteFailed; try w.splatByteAll(' ', depth * package_indent); try w.print("{d}:\n", .{ i }); - try cp_info.?.indentedFormat(w, depth, package_indent + 1, constant_pool); + try info.indentedFormat(w, depth, package_indent + 1, constant_pool); } }, .module_main_class => |attr| { @@ -513,15 +503,11 @@ pub const AttributeInfo = union(enum) { class_indent += 1; defer class_indent -= 1; - const index = class_index - 1; - - if (index >= constant_pool.len) return error.WriteFailed; - const cp_info = constant_pool[index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return error.WriteFailed; + const info = constant_pool.getTag(class_index, .class) catch return error.WriteFailed; try w.splatByteAll(' ', depth * class_indent); try w.print("{d}:\n", .{ i }); - try cp_info.?.indentedFormat(w, depth, class_indent + 1, constant_pool); + try info.indentedFormat(w, depth, class_indent + 1, constant_pool); } }, .record => |attr| { @@ -545,15 +531,11 @@ pub const AttributeInfo = union(enum) { class_indent += 1; defer class_indent -= 1; - const index = class_index - 1; - - if (index >= constant_pool.len) return error.WriteFailed; - const cp_info = constant_pool[index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return error.WriteFailed; + const info = constant_pool.getTag(class_index, .class) catch return error.WriteFailed; try w.splatByteAll(' ', depth * class_indent); try w.print("{d}:\n", .{ i }); - try cp_info.?.indentedFormat(w, depth, class_indent + 1, constant_pool); + try info.indentedFormat(w, depth, class_indent + 1, constant_pool); } }, else => {}, @@ -580,13 +562,8 @@ pub const NewAttribute = struct { allocator.free(self.info); } - pub fn attributeName(self: *const Self, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const attribute_name_index = self.attribute_name_index - 1; - if (attribute_name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[attribute_name_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - - return cp_info.?; + pub fn attributeName(self: *const Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.attribute_name_index, .utf8); } }; @@ -601,13 +578,8 @@ pub const ConstantValue = struct { }; } - pub fn constantValue(self: *const Self, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const constant_value_index = self.constant_value_index - 1; - if (constant_value_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[constant_value_index]; - if (cp_info == null) return ResolveError.InvalidConstantType; - - return cp_info.?; + pub fn constantValue(self: *const Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.get(self.constant_value_index); } }; @@ -631,7 +603,7 @@ pub const Code = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPool.Info, + constant_pool: ConstantPool, ) std.Io.Writer.Error!void { try w.splatByteAll(' ', depth * indent); try w.print("start_pc: {d}\n", .{ self.start_pc }); @@ -650,17 +622,12 @@ pub const Code = struct { } } - pub fn catchType(self: *const ExceptionHandler, constant_pool: []const ?ConstantPool.Info) ResolveError!?ConstantPool.Info { - if (self.catch_type == 0) return null; - const catch_type = self.catch_type - 1; - if (catch_type >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[catch_type]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn catchType(self: *const ExceptionHandler, constant_pool: ConstantPool) ResolveError!?ConstantPool.Info { + return constant_pool.getTagOptional(self.catch_type, .class); } }; - pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPool.Info, allocator: std.mem.Allocator) (ParseError || ResolveError)!Self { + pub fn parse(input: *std.Io.Reader, constant_pool: ConstantPool, allocator: std.mem.Allocator) (ParseError || ResolveError)!Self { const max_stack = try input.takeInt(u16, .big); const max_locals = try input.takeInt(u16, .big); @@ -947,7 +914,7 @@ pub const InnerClasses = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPool.Info, + constant_pool: ConstantPool, ) std.Io.Writer.Error!void { try w.splatByteAll(' ', depth * indent); try w.print("flags: {f}\n", .{ self.inner_class_access_flags }); @@ -972,32 +939,16 @@ pub const InnerClasses = struct { } } - pub fn innerClass(self: *const InnerClass, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const inner_class_info_index = self.inner_class_info_index - 1; - if (inner_class_info_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[inner_class_info_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn innerClass(self: *const InnerClass, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.inner_class_info_index, .class); } - pub fn outerClass(self: *const InnerClass, constant_pool: []const ?ConstantPool.Info) ResolveError!?ConstantPool.Info { - if (self.outer_class_info_index == 0) return null; - const outer_class_info_index = self.outer_class_info_index - 1; - if (outer_class_info_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - - const cp_info = constant_pool[outer_class_info_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn outerClass(self: *const InnerClass, constant_pool: ConstantPool) ResolveError!?ConstantPool.Info { + return constant_pool.getTagOptional(self.outer_class_info_index, .class); } - pub fn innerName(self: *const InnerClass, constant_pool: []const ?ConstantPool.Info) ResolveError!?ConstantPool.Info { - if (self.inner_name_index == 0) return null; - const inner_name_index = self.inner_name_index - 1; - if (inner_name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - - const cp_info = constant_pool[inner_name_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn innerName(self: *const InnerClass, constant_pool: ConstantPool) ResolveError!?ConstantPool.Info { + return constant_pool.getTagOptional(self.inner_name_index, .utf8); } }; @@ -1037,21 +988,12 @@ pub const EnclosingMethod = struct { }; } - pub fn class(self: *const EnclosingMethod, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const class_index = self.class_index - 1; - if (class_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[class_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn class(self: *const EnclosingMethod, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.class_index, .class); } - pub fn method(self: *const EnclosingMethod, constant_pool: []const ?ConstantPool.Info) ResolveError!?ConstantPool.Info { - if (self.method_index == 0) return null; - const method_index = self.method_index - 1; - if (method_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[method_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .name_and_type) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn method(self: *const EnclosingMethod, constant_pool: ConstantPool) ResolveError!?ConstantPool.Info { + return constant_pool.getTagOptional(self.method_index, .name_and_type); } }; @@ -1068,12 +1010,8 @@ pub const Signature = struct { }; } - pub fn signature(self: *const Signature, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const signature_index = self.signature_index - 1; - if (signature_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[signature_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn signature(self: *const Signature, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.signature_index, .utf8); } }; @@ -1088,12 +1026,8 @@ pub const SourceFile = struct { }; } - pub fn sourceFile(self: *const SourceFile, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const source_file_index = self.source_file_index - 1; - if (source_file_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[source_file_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn sourceFile(self: *const SourceFile, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.source_file_index, .utf8); } }; @@ -1174,7 +1108,7 @@ pub const LocalVariableTable = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPool.Info, + constant_pool: ConstantPool, ) std.Io.Writer.Error!void { try w.splatByteAll(' ', depth * indent); try w.print("start_pc: {d}\n", .{ self.start_pc }); @@ -1193,20 +1127,12 @@ pub const LocalVariableTable = struct { try descriptor_.indentedFormat(w, depth, indent + 1, constant_pool); } - pub fn name(self: *const LocalVariable, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const name_index = self.name_index - 1; - if (name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[name_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn name(self: *const LocalVariable, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.name_index, .utf8); } - pub fn descriptor(self: *const LocalVariable, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const descriptor_index = self.descriptor_index - 1; - if (descriptor_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[descriptor_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn descriptor(self: *const LocalVariable, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.descriptor_index, .utf8); } }; @@ -1251,7 +1177,7 @@ pub const LocalVariableTypeTable = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPool.Info, + constant_pool: ConstantPool, ) std.Io.Writer.Error!void { try w.splatByteAll(' ', depth * indent); try w.print("start_pc: {d}\n", .{ self.start_pc }); @@ -1270,20 +1196,12 @@ pub const LocalVariableTypeTable = struct { try signature_.indentedFormat(w, depth, indent + 1, constant_pool); } - pub fn name(self: *const LocalVariableType, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const name_index = self.name_index - 1; - if (name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[name_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn name(self: *const LocalVariableType, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.name_index, .utf8); } - pub fn signature(self: *const LocalVariableType, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const signature_index = self.signature_index - 1; - if (signature_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[signature_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn signature(self: *const LocalVariableType, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.signature_index, .utf8); } }; @@ -1623,7 +1541,7 @@ pub const BootstrapMethods = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPool.Info, + constant_pool: ConstantPool, ) std.Io.Writer.Error!void { const bootstrap_method = self.bootstrapMethod(constant_pool) catch return error.WriteFailed; try w.splatByteAll(' ', depth * indent); @@ -1637,24 +1555,16 @@ pub const BootstrapMethods = struct { bootstrap_argument_indent += 1; defer bootstrap_argument_indent -= 1; - const index = bootstrap_argument - 1; - - if (index >= constant_pool.len) return error.WriteFailed; - const cp_info = constant_pool[index]; - if (cp_info == null or !@as(ConstantPool.Info.Tag, cp_info.?).loadable()) return error.WriteFailed; + const info = constant_pool.getLoadable(bootstrap_argument) catch return error.WriteFailed; try w.splatByteAll(' ', depth * bootstrap_argument_indent); try w.print("{d}:\n", .{ i }); - try cp_info.?.indentedFormat(w, depth, bootstrap_argument_indent + 1, constant_pool); + try info.indentedFormat(w, depth, bootstrap_argument_indent + 1, constant_pool); } } - pub fn bootstrapMethod(self: *const BootstrapMethod, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const bootstrap_method_ref = self.bootstrap_method_ref - 1; - if (bootstrap_method_ref >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[bootstrap_method_ref]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .method_handle) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn bootstrapMethod(self: *const BootstrapMethod, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.bootstrap_method_ref, .method_handle); } }; @@ -1711,7 +1621,7 @@ pub const MethodParameters = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPool.Info, + constant_pool: ConstantPool, ) std.Io.Writer.Error!void { try w.splatByteAll(' ', depth * indent); try w.print("flags: {f}\n", .{ self.access_flags }); @@ -1722,12 +1632,8 @@ pub const MethodParameters = struct { try name_.indentedFormat(w, depth, indent + 1, constant_pool); } - pub fn name(self: *const Parameter, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const name_index = self.name_index - 1; - if (name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[name_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn name(self: *const Parameter, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.name_index, .utf8); } }; @@ -1787,7 +1693,7 @@ pub const Module = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPool.Info, + constant_pool: ConstantPool, ) std.Io.Writer.Error!void { const requires_ = self.requires(constant_pool) catch return error.WriteFailed; try w.splatByteAll(' ', depth * indent); @@ -1805,21 +1711,12 @@ pub const Module = struct { } } - pub fn requires(self: *const Requires, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const requires_index = self.requires_index - 1; - if (requires_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[requires_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .module) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn requires(self: *const Requires, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.requires_index, .module); } - pub fn requiresVersion(self: *const Requires, constant_pool: []const ?ConstantPool.Info) ResolveError!?ConstantPool.Info { - if (self.requires_version_index == 0) return null; - const requires_version_index = self.requires_version_index - 1; - if (requires_version_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[requires_version_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn requiresVersion(self: *const Requires, constant_pool: ConstantPool) ResolveError!?ConstantPool.Info { + return constant_pool.getTagOptional(self.requires_version_index, .utf8); } }; @@ -1838,7 +1735,7 @@ pub const Module = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPool.Info, + constant_pool: ConstantPool, ) std.Io.Writer.Error!void { const exports_ = self.exports(constant_pool) catch return error.WriteFailed; try w.splatByteAll(' ', depth * indent); @@ -1855,24 +1752,16 @@ pub const Module = struct { exports_to_indent += 1; defer exports_to_indent -= 1; - const index = exports_to_index - 1; - - if (index >= constant_pool.len) return error.WriteFailed; - const cp_info = constant_pool[index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .module) return error.WriteFailed; + const info = constant_pool.getTag(exports_to_index, .module) catch return error.WriteFailed; try w.splatByteAll(' ', depth * exports_to_indent); try w.print("{d}:\n", .{ i }); - try cp_info.?.indentedFormat(w, depth, exports_to_indent + 1, constant_pool); + try info.indentedFormat(w, depth, exports_to_indent + 1, constant_pool); } } - pub fn exports(self: *const Exports, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const exports_index = self.exports_index - 1; - if (exports_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[exports_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .package) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn exports(self: *const Exports, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.exports_index, .package); } }; @@ -1891,7 +1780,7 @@ pub const Module = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPool.Info, + constant_pool: ConstantPool, ) std.Io.Writer.Error!void { const opens_ = self.opens(constant_pool) catch return error.WriteFailed; try w.splatByteAll(' ', depth * indent); @@ -1908,24 +1797,16 @@ pub const Module = struct { opens_to_indent += 1; defer opens_to_indent -= 1; - const index = opens_to_index - 1; - - if (index >= constant_pool.len) return error.WriteFailed; - const cp_info = constant_pool[index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .module) return error.WriteFailed; + const info = constant_pool.getTag(opens_to_index, .module) catch return error.WriteFailed; try w.splatByteAll(' ', depth * opens_to_indent); try w.print("{d}:\n", .{ i }); - try cp_info.?.indentedFormat(w, depth, opens_to_indent + 1, constant_pool); + try info.indentedFormat(w, depth, opens_to_indent + 1, constant_pool); } } - pub fn opens(self: *const Opens, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const opens_index = self.opens_index - 1; - if (opens_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[opens_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .package) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn opens(self: *const Opens, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.opens_index, .package); } }; @@ -1938,7 +1819,7 @@ pub const Module = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPool.Info, + constant_pool: ConstantPool, ) std.Io.Writer.Error!void { const provides_ = self.provides(constant_pool) catch return error.WriteFailed; try w.splatByteAll(' ', depth * indent); @@ -1952,24 +1833,16 @@ pub const Module = struct { provides_with_indent += 1; defer provides_with_indent -= 1; - const index = provides_with_index - 1; - - if (index >= constant_pool.len) return error.WriteFailed; - const cp_info = constant_pool[index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return error.WriteFailed; + const info = constant_pool.getTag(provides_with_index, .class) catch return error.WriteFailed; try w.splatByteAll(' ', depth * provides_with_indent); try w.print("{d}:\n", .{ i }); - try cp_info.?.indentedFormat(w, depth, provides_with_indent + 1, constant_pool); + try info.indentedFormat(w, depth, provides_with_indent + 1, constant_pool); } } - pub fn provides(self: *const Provides, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const provides_index = self.provides_index - 1; - if (provides_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[provides_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn provides(self: *const Provides, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.provides_index, .class); } }; @@ -2088,7 +1961,7 @@ pub const Module = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPool.Info, + constant_pool: ConstantPool, ) std.Io.Writer.Error!void { const module_name = self.moduleName(constant_pool) catch return error.WriteFailed; try w.splatByteAll(' ', depth * indent); @@ -2148,15 +2021,11 @@ pub const Module = struct { uses_indent += 1; defer uses_indent -= 1; - const index = uses_index - 1; - - if (index >= constant_pool.len) return error.WriteFailed; - const cp_info = constant_pool[index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return error.WriteFailed; + const info = constant_pool.getTag(uses_index, .class) catch return error.WriteFailed; try w.splatByteAll(' ', depth * uses_indent); try w.print("{d}:\n", .{ i }); - try cp_info.?.indentedFormat(w, depth, uses_indent + 1, constant_pool); + try info.indentedFormat(w, depth, uses_indent + 1, constant_pool); } try w.splatByteAll(' ', depth * indent); @@ -2172,21 +2041,12 @@ pub const Module = struct { } } - pub fn moduleName(self: *const Module, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const module_name_index = self.module_name_index - 1; - if (module_name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[module_name_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn moduleName(self: *const Module, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.module_name_index, .utf8); } - pub fn moduleVersion(self: *const Module, constant_pool: []const ?ConstantPool.Info) ResolveError!?ConstantPool.Info { - if (self.module_version_index == 0) return null; - const module_version_index = self.module_version_index - 1; - if (module_version_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[module_version_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn moduleVersion(self: *const Module, constant_pool: ConstantPool) ResolveError!?ConstantPool.Info { + return constant_pool.getTagOptional(self.module_version_index, .utf8); } }; @@ -2224,12 +2084,8 @@ pub const ModuleMainClass = struct { }; } - pub fn mainClass(self: *const ModuleMainClass, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const main_class_index = self.main_class_index - 1; - if (main_class_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[main_class_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn mainClass(self: *const ModuleMainClass, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.main_class_index, .class); } }; @@ -2244,12 +2100,8 @@ pub const NestHost = struct { }; } - pub fn hostClass(self: *const NestHost, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const host_class_index = self.host_class_index - 1; - if (host_class_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[host_class_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn hostClass(self: *const NestHost, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.host_class_index, .class); } }; @@ -2285,7 +2137,7 @@ pub const Record = struct { descriptor_index: u16, attributes: []AttributeInfo, - pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPool.Info, allocator: std.mem.Allocator) (ParseError || ResolveError)!RecordComponentInfo { + pub fn parse(input: *std.Io.Reader, constant_pool: ConstantPool, allocator: std.mem.Allocator) (ParseError || ResolveError)!RecordComponentInfo { const name_index = try input.takeInt(u16, .big); const descriptor_index = try input.takeInt(u16, .big); @@ -2315,7 +2167,7 @@ pub const Record = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPool.Info, + constant_pool: ConstantPool, ) std.Io.Writer.Error!void { const name_ = self.name(constant_pool) catch return error.WriteFailed; try w.splatByteAll(' ', depth * indent); @@ -2336,29 +2188,20 @@ pub const Record = struct { try w.splatByteAll(' ', depth * attr_indent); try w.print("{d}:\n", .{ i }); - try attr.indentedFormat(w, depth, attr_indent + 1, constant_pool); } } - pub fn name(self: *const RecordComponentInfo, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const name_index = self.name_index - 1; - if (name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[name_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn name(self: *const RecordComponentInfo, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.name_index, .utf8); } - pub fn descriptor(self: *const RecordComponentInfo, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const descriptor_index = self.descriptor_index - 1; - if (descriptor_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[descriptor_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn descriptor(self: *const RecordComponentInfo, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.descriptor_index, .utf8); } }; - pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPool.Info, allocator: std.mem.Allocator) (ParseError || ResolveError)!Self { + pub fn parse(input: *std.Io.Reader, constant_pool: ConstantPool, allocator: std.mem.Allocator) (ParseError || ResolveError)!Self { const components_count = try input.takeInt(u16, .big); const components = try allocator.alloc(RecordComponentInfo, components_count); for (components) |*component| { diff --git a/src/Class/ConstantPool.zig b/src/Class/ConstantPool.zig index cdf4063..17e71c2 100644 --- a/src/Class/ConstantPool.zig +++ b/src/Class/ConstantPool.zig @@ -5,6 +5,10 @@ const AttributeInfo = Class.AttributeInfo; const ParseError = Class.ParseError; const ResolveError = Class.ResolveError; +constant_pool: []?Info, + +const Self = @This(); + pub const Info = union(Info.Tag) { class: Info.Class, field_ref: FieldRef, @@ -54,14 +58,8 @@ pub const Info = union(Info.Tag) { pub const Class = struct { name_index: u16, - const Self = @This(); - - pub fn name(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { - const name_index = self.name_index - 1; - if (name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[name_index]; - if (cp_info == null or @as(Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn name(self: *const Info.Class, constant_pool: Self) ResolveError!Info { + return constant_pool.getTag(self.name_index, .utf8); } }; @@ -69,22 +67,12 @@ pub const Info = union(Info.Tag) { class_index: u16, name_and_type_index: u16, - const Self = @This(); - - pub fn class(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { - const class_index = self.class_index - 1; - if (class_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[class_index]; - if (cp_info == null or @as(Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn class(self: *const FieldRef, constant_pool: Self) ResolveError!Info { + return constant_pool.getTag(self.class_index, .class); } - pub fn nameAndType(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { - const name_and_type_index = self.name_and_type_index - 1; - if (name_and_type_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[name_and_type_index]; - if (cp_info == null or @as(Tag, cp_info.?) != .name_and_type) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn nameAndType(self: *const FieldRef, constant_pool: Self) ResolveError!Info { + return constant_pool.getTag(self.name_and_type_index, .name_and_type); } }; @@ -92,22 +80,12 @@ pub const Info = union(Info.Tag) { class_index: u16, name_and_type_index: u16, - const Self = @This(); - - pub fn class(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { - const class_index = self.class_index - 1; - if (class_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[class_index]; - if (cp_info == null or @as(Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn class(self: *const MethodRef, constant_pool: Self) ResolveError!Info { + return constant_pool.getTag(self.class_index, .class); } - pub fn nameAndType(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { - const name_and_type_index = self.name_and_type_index - 1; - if (name_and_type_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[name_and_type_index]; - if (cp_info == null or @as(Tag, cp_info.?) != .name_and_type) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn nameAndType(self: *const MethodRef, constant_pool: Self) ResolveError!Info { + return constant_pool.getTag(self.name_and_type_index, .name_and_type); } }; @@ -115,36 +93,20 @@ pub const Info = union(Info.Tag) { class_index: u16, name_and_type_index: u16, - const Self = @This(); - - pub fn class(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { - const class_index = self.class_index - 1; - if (class_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[class_index]; - if (cp_info == null or @as(Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn class(self: *const InterfaceMethodRef, constant_pool: Self) ResolveError!Info { + return constant_pool.getTag(self.class_index, .class); } - pub fn nameAndType(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { - const name_and_type_index = self.name_and_type_index - 1; - if (name_and_type_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[name_and_type_index]; - if (cp_info == null or @as(Tag, cp_info.?) != .name_and_type) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn nameAndType(self: *const InterfaceMethodRef, constant_pool: Self) ResolveError!Info { + return constant_pool.getTag(self.name_and_type_index, .name_and_type); } }; pub const String = struct { string_index: u16, - const Self = @This(); - - pub fn string(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { - const string_index = self.string_index - 1; - if (string_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[string_index]; - if (cp_info == null or @as(Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn string(self: *const String, constant_pool: Self) ResolveError!Info { + return constant_pool.getTag(self.string_index, .utf8); } }; @@ -170,22 +132,12 @@ pub const Info = union(Info.Tag) { name_index: u16, descriptor_index: u16, - const Self = @This(); - - pub fn name(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { - const name_index = self.name_index - 1; - if (name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[name_index]; - if (cp_info == null or @as(Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn name(self: *const NameAndType, constant_pool: Self) ResolveError!Info { + return constant_pool.getTag(self.name_index, .utf8); } - pub fn descriptor(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { - const descriptor_index = self.descriptor_index - 1; - if (descriptor_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[descriptor_index]; - if (cp_info == null or @as(Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn descriptor(self: *const NameAndType, constant_pool: Self) ResolveError!Info { + return constant_pool.getTag(self.descriptor_index, .utf8); } }; @@ -197,8 +149,6 @@ pub const Info = union(Info.Tag) { reference_kind: Kind, reference_index: u16, - const Self = @This(); - pub const Kind = enum(u8) { get_field = 1, get_static = 2, @@ -211,22 +161,20 @@ pub const Info = union(Info.Tag) { invoke_interface = 9, }; - pub fn reference(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { - const reference_index = self.reference_index - 1; - if (reference_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[reference_index]; + pub fn reference(self: *const MethodHandle, constant_pool: Self) ResolveError!Info { + const info = try constant_pool.get(self.reference_index); return switch (self.reference_kind) { .get_field, .get_static, .put_field, .put_static => blk: { - if (cp_info == null or @as(Tag, cp_info.?) != .field_ref) break :blk ResolveError.InvalidConstantType; - break :blk cp_info.?; + if (@as(Tag, info) != .field_ref) break :blk ResolveError.InvalidConstantType; + break :blk info; }, .invoke_virtual, .invoke_static, .invoke_special, .new_invoke_special => blk: { - if (cp_info == null or @as(Tag, cp_info.?) != .method_ref) break :blk ResolveError.InvalidConstantType; - break :blk cp_info.?; + if (@as(Tag, info) != .method_ref) break :blk ResolveError.InvalidConstantType; + break :blk info; }, .invoke_interface => blk: { - if (cp_info == null or @as(Tag, cp_info.?) != .interface_method_ref) break :blk ResolveError.InvalidConstantType; - break :blk cp_info.?; + if (@as(Tag, info) != .interface_method_ref) break :blk ResolveError.InvalidConstantType; + break :blk info; }, }; } @@ -235,14 +183,8 @@ pub const Info = union(Info.Tag) { pub const MethodType = struct { descriptor_index: u16, - const Self = @This(); - - pub fn descriptor(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { - const descriptor_index = self.descriptor_index - 1; - if (descriptor_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[descriptor_index]; - if (cp_info == null or @as(Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn descriptor(self: *const MethodType, constant_pool: Self) ResolveError!Info { + return constant_pool.getTag(self.descriptor_index, .utf8); } }; @@ -250,14 +192,8 @@ pub const Info = union(Info.Tag) { bootstrap_method_attr_index: u16, name_and_type_index: u16, - const Self = @This(); - - pub fn nameAndType(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { - const name_and_type_index = self.name_and_type_index - 1; - if (name_and_type_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[name_and_type_index]; - if (cp_info == null or @as(Tag, cp_info.?) != .name_and_type) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn nameAndType(self: *const Dynamic, constant_pool: Self) ResolveError!Info { + return constant_pool.getTag(self.name_and_type_index, .name_and_type); } }; @@ -265,42 +201,24 @@ pub const Info = union(Info.Tag) { bootstrap_method_attr_index: u16, name_and_type_index: u16, - const Self = @This(); - - pub fn nameAndType(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { - const name_and_type_index = self.name_and_type_index - 1; - if (name_and_type_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[name_and_type_index]; - if (cp_info == null or @as(Tag, cp_info.?) != .name_and_type) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn nameAndType(self: *const InvokeDynamic, constant_pool: Self) ResolveError!Info { + return constant_pool.getTag(self.name_and_type_index, .name_and_type); } }; pub const Module = struct { name_index: u16, - const Self = @This(); - - pub fn name(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { - const name_index = self.name_index - 1; - if (name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[name_index]; - if (cp_info == null or @as(Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn name(self: *const Module, constant_pool: Self) ResolveError!Info { + return constant_pool.getTag(self.name_index, .utf8); } }; pub const Package = struct { name_index: u16, - const Self = @This(); - - pub fn name(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { - const name_index = self.name_index - 1; - if (name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[name_index]; - if (cp_info == null or @as(Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; + pub fn name(self: *const Package, constant_pool: Self) ResolveError!Info { + return constant_pool.getTag(self.name_index, .utf8); } }; @@ -450,7 +368,7 @@ pub const Info = union(Info.Tag) { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?Info, + constant_pool: Self, ) std.Io.Writer.Error!void { try w.splatByteAll(' ', depth * indent); try w.print("constant_value_type: {s}\n", .{ @tagName(self.*) }); @@ -579,3 +497,71 @@ pub const Info = union(Info.Tag) { } } }; + +pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self { + const constant_pool_size = try input.takeInt(u16, .big); + const constant_pool = try allocator.alloc(?Info, constant_pool_size - 1); + errdefer allocator.free(constant_pool); + + var i: usize = 0; + while (i < constant_pool_size - 1) { + defer i += 1; + + const info: Info = try .parse(input, allocator); + constant_pool[i] = info; + + switch (info) { + .long, .double => { + i += 1; + constant_pool[i] = null; + }, + else => {}, + } + } + + return .{ + .constant_pool = constant_pool, + }; +} + +pub fn deinit(self: *Self, allocator: std.mem.Allocator) void { + for (self.constant_pool) |*info| { + if (info.*) |*c| c.deinit(allocator); + } + allocator.free(self.constant_pool); +} + +pub fn get(self: *const Self, index: u16) ResolveError!Info { + const actual_index = index - 1; + if (actual_index >= self.constant_pool.len) return ResolveError.InvalidConstantPoolIndex; + const info = self.constant_pool[actual_index]; + if (info == null) return ResolveError.InvalidConstantType; + return info.?; +} + +pub fn getOptional(self: *const Self, index: u16) ResolveError!?Info { + if (index == 0) return null; + return self.get(index); +} + +pub fn getTag(self: *const Self, index: u16, expected_tag: Info.Tag) ResolveError!Info { + const info = try self.get(index); + if (@as(Info.Tag, info) != expected_tag) return ResolveError.InvalidConstantType; + return info; +} + +pub fn getTagOptional(self: *const Self, index: u16, expected_tag: Info.Tag) ResolveError!?Info { + if (index == 0) return null; + return try self.getTag(index, expected_tag); +} + +pub fn getLoadable(self: *const Self, index: u16) ResolveError!Info { + const info = try self.get(index); + if (!@as(Info.Tag, info).loadable()) return ResolveError.InvalidConstantType; + return info; +} + +pub fn getLoadableOptional(self: *const Self, index: u16) ResolveError!?Info { + if (index == 0) return null; + return self.getLoadable(index); +} diff --git a/src/Class/FieldInfo.zig b/src/Class/FieldInfo.zig index 12a75a3..46746e6 100644 --- a/src/Class/FieldInfo.zig +++ b/src/Class/FieldInfo.zig @@ -26,7 +26,7 @@ pub const FieldAccessFlags = EnumFlags(enum(u16) { @"enum" = 0x4000, }); -pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPool.Info, allocator: std.mem.Allocator) !Self { +pub fn parse(input: *std.Io.Reader, constant_pool: ConstantPool, allocator: std.mem.Allocator) !Self { const access_flags: FieldAccessFlags = .{ .mask = try input.takeInt(u16, .big) }; const name_index = try input.takeInt(u16, .big); const descriptor_index = try input.takeInt(u16, .big); @@ -51,7 +51,7 @@ pub fn indentedFormat( w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPool.Info, + constant_pool: ConstantPool, ) std.Io.Writer.Error!void { try w.splatByteAll(' ', depth * indent); try w.print("flags: {f}\n", .{ self.access_flags }); @@ -80,19 +80,11 @@ pub fn indentedFormat( } } -pub fn name(self: *const Self, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const name_index = self.name_index - 1; - if (name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[name_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; +pub fn name(self: *const Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.name_index, .utf8); } -pub fn descriptor(self: *const Self, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const descriptor_index = self.descriptor_index - 1; - if (descriptor_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[descriptor_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; +pub fn descriptor(self: *const Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.descriptor_index, .utf8); } diff --git a/src/Class/MethodInfo.zig b/src/Class/MethodInfo.zig index f58a7bf..2650061 100644 --- a/src/Class/MethodInfo.zig +++ b/src/Class/MethodInfo.zig @@ -29,7 +29,7 @@ pub const MethodAccessFlags = EnumFlags(enum(u16) { synthetic = 0x1000, }); -pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPool.Info, allocator: std.mem.Allocator) !Self { +pub fn parse(input: *std.Io.Reader, constant_pool: ConstantPool, allocator: std.mem.Allocator) !Self { const access_flags: MethodAccessFlags = .{ .mask = try input.takeInt(u16, .big) }; const name_index = try input.takeInt(u16, .big); const descriptor_index = try input.takeInt(u16, .big); @@ -54,7 +54,7 @@ pub fn indentedFormat( w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPool.Info, + constant_pool: ConstantPool, ) std.Io.Writer.Error!void { try w.splatByteAll(' ', depth * indent); try w.print("flags: {f}\n", .{ self.access_flags }); @@ -83,19 +83,10 @@ pub fn indentedFormat( } } -pub fn name(self: *const Self, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const name_index = self.name_index - 1; - if (name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[name_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; +pub fn name(self: *const Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.name_index, .utf8); } -pub fn descriptor(self: *const Self, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { - const descriptor_index = self.descriptor_index - 1; - if (descriptor_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[descriptor_index]; - if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; +pub fn descriptor(self: *const Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { + return constant_pool.getTag(self.descriptor_index, .utf8); } - diff --git a/src/main.zig b/src/main.zig index 922c825..8c4831e 100644 --- a/src/main.zig +++ b/src/main.zig @@ -52,16 +52,6 @@ pub fn main(init: std.process.Init) !void { }; defer class.deinit(); - if (@import("builtin").mode == .Debug) { - for (class.constant_pool, 1..) |cp_info, i| { - if (cp_info) |info| { - std.debug.print("#{d} = {s}\t{f}\n", .{ i, @tagName(info), info }); - } else { - std.debug.print("#{d} = null\n", .{ i }); - } - } - } - try stdout.print("{f}", .{ class }); try stdout.flush();