From 3a5fd90d14d54f308b20df60d58b76bdb5cb8d3e Mon Sep 17 00:00:00 2001 From: ktkk Date: Mon, 6 Jul 2026 21:55:57 +0200 Subject: [PATCH] Format stack map table attribute --- src/Class/AttributeInfo.zig | 137 ++++++++++++++++++++++++++++++- testsuite/classes/java/Main.java | 19 +++-- 2 files changed, 149 insertions(+), 7 deletions(-) diff --git a/src/Class/AttributeInfo.zig b/src/Class/AttributeInfo.zig index 6bbf7b5..8747ed2 100644 --- a/src/Class/AttributeInfo.zig +++ b/src/Class/AttributeInfo.zig @@ -332,7 +332,20 @@ pub const AttributeInfo = union(enum) { try a.indentedFormat(w, depth, attr_indent + 1, constant_pool); } }, - //.stack_map_table, + .stack_map_table => |attr| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("entries:\n"); + var stack_map_frame_indent = indent; + for (attr.entries, 0..) |*stack_map_frame, i| { + stack_map_frame_indent += 1; + defer stack_map_frame_indent -= 1; + + try w.splatByteAll(' ', depth * stack_map_frame_indent); + try w.print("{d}:\n", .{ i }); + + try stack_map_frame.indentedFormat(w, depth, stack_map_frame_indent + 1, constant_pool); + } + }, .exceptions => |attr| { try w.splatByteAll(' ', depth * indent); _ = try w.write("exceptions:\n"); @@ -791,6 +804,103 @@ pub const StackMapTable = struct { else => {}, } } + + pub fn indentedFormat( + self: *const StackMapFrame, + w: *std.Io.Writer, + depth: usize, + indent: u8, + constant_pool: ConstantPool, + ) std.Io.Writer.Error!void { + try w.splatByteAll(' ', depth * indent); + try w.print("frame_type: {s}\n", .{ @tagName(self.*) }); + + switch (self.*) { + .same_locals_1_stack_item_frame => |same_locals_1_stack_item_frame| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("stack:\n"); + var stack_indent = indent; + for (&same_locals_1_stack_item_frame.stack, 0..) |*info, i| { + stack_indent += 1; + defer stack_indent -= 1; + + try w.splatByteAll(' ', depth * stack_indent); + try w.print("{d}:\n", .{ i }); + + try info.indentedFormat(w, depth, stack_indent + 1, constant_pool); + } + }, + .same_locals_1_stack_item_frame_extended => |same_locals_1_stack_item_frame_extended| { + try w.splatByteAll(' ', depth * indent); + try w.print("offset_delta: {d}\n", .{ same_locals_1_stack_item_frame_extended.offset_delta }); + + try w.splatByteAll(' ', depth * indent); + _ = try w.write("stack:\n"); + var stack_indent = indent; + for (&same_locals_1_stack_item_frame_extended.stack, 0..) |*info, i| { + stack_indent += 1; + defer stack_indent -= 1; + + try w.splatByteAll(' ', depth * stack_indent); + try w.print("{d}:\n", .{ i }); + + try info.indentedFormat(w, depth, stack_indent + 1, constant_pool); + } + }, + .chop_frame => |chop_frame| { + try w.splatByteAll(' ', depth * indent); + try w.print("offset_delta: {d}\n", .{ chop_frame.offset_delta }); + }, + .append_frame => |append_frame| { + try w.splatByteAll(' ', depth * indent); + try w.print("offset_delta: {d}\n", .{ append_frame.offset_delta }); + + try w.splatByteAll(' ', depth * indent); + _ = try w.write("locals:\n"); + var locals_indent = indent; + for (append_frame.locals, 0..) |*info, i| { + locals_indent += 1; + defer locals_indent -= 1; + + try w.splatByteAll(' ', depth * locals_indent); + try w.print("{d}:\n", .{ i }); + + try info.indentedFormat(w, depth, locals_indent + 1, constant_pool); + } + }, + .full_frame => |full_frame| { + try w.splatByteAll(' ', depth * indent); + try w.print("offset_delta: {d}\n", .{ full_frame.offset_delta }); + + try w.splatByteAll(' ', depth * indent); + _ = try w.write("locals:\n"); + var locals_indent = indent; + for (full_frame.locals, 0..) |*info, i| { + locals_indent += 1; + defer locals_indent -= 1; + + try w.splatByteAll(' ', depth * locals_indent); + try w.print("{d}:\n", .{ i }); + + try info.indentedFormat(w, depth, locals_indent + 1, constant_pool); + } + + try w.splatByteAll(' ', depth * indent); + _ = try w.write("stack:\n"); + var stack_indent = indent; + for (full_frame.stack, 0..) |*info, i| { + stack_indent += 1; + defer stack_indent -= 1; + + try w.splatByteAll(' ', depth * stack_indent); + try w.print("{d}:\n", .{ i }); + + try info.indentedFormat(w, depth, stack_indent + 1, constant_pool); + } + }, + else => {}, + } + } }; pub const VerificationTypeInfo = union(VerificationTypeInfo.Tag) { @@ -852,6 +962,31 @@ pub const StackMapTable = struct { }, }; } + + pub fn indentedFormat( + self: *const VerificationTypeInfo, + w: *std.Io.Writer, + depth: usize, + indent: u8, + constant_pool: ConstantPool, + ) std.Io.Writer.Error!void { + try w.splatByteAll(' ', depth * indent); + try w.print("tag: {s}\n", .{ @tagName(self.*) }); + + switch (self.*) { + .object => |object| { + const class = object.class(constant_pool) catch return error.WriteFailed; + try w.splatByteAll(' ', depth * indent); + _ = try w.write("class:\n"); + try class.indentedFormat(w, depth, indent + 1, constant_pool); + }, + .uninitialized => |uninitialized| { + try w.splatByteAll(' ', depth * indent); + try w.print("offset: {d}\n", .{ uninitialized.offset }); + }, + else => {}, + } + } }; pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self { diff --git a/testsuite/classes/java/Main.java b/testsuite/classes/java/Main.java index ec77f66..01f523a 100644 --- a/testsuite/classes/java/Main.java +++ b/testsuite/classes/java/Main.java @@ -1,18 +1,26 @@ import java.util.function.Supplier; -@CustomAttribute public class Main implements Runnable, Supplier, Interface { private static final String name = "John"; private static final int number = 42; private static final double funnyNumber = 6.9; - public static void main() { - new Main().sayHello(); + public static void main(String[] args) { + final var main = new Main(); + main.sayHello(); + + try { + main.throwSomething(); + } catch (Throwable e) { + System.err.println("Caught " + e.getMessage()); + } finally { + System.err.println("Finally block"); + } } - + @Override public void run() { - Main.main(); + Main.main(new String[] { "Hello" }); } @Override @@ -38,4 +46,3 @@ public class Main implements Runnable, Supplier, Interface { private static final String name = "Inner John"; } } -