feature/instructions #1

Merged
katkak merged 6 commits from feature/instructions into master 2026-09-07 20:36:37 +02:00
2 changed files with 191 additions and 11 deletions
Showing only changes of commit 6d8e9d05f9 - Show all commits

View file

@ -319,7 +319,9 @@ pub const AttributeInfo = union(enum) {
defer instr_indent -= 1; defer instr_indent -= 1;
try w.splatByteAll(' ', depth * instr_indent); try w.splatByteAll(' ', depth * instr_indent);
try w.print("{d}: {t}\n", .{ i, instr }); try w.print("{d}:\n", .{ i });
try instr.indentedFormat(w, depth, instr_indent + 1, constant_pool);
} }
try w.splatByteAll(' ', depth * indent); try w.splatByteAll(' ', depth * indent);

View file

@ -255,7 +255,7 @@ fn Branch(comptime T: type) type {
const bytes = bits / 8; const bytes = bits / 8;
return struct { return struct {
branch: T, branch_offset: T,
const Self = @This(); const Self = @This();
@ -263,7 +263,7 @@ fn Branch(comptime T: type) type {
defer byte_index.* += bytes; defer byte_index.* += bytes;
return .{ return .{
.branch = try input.takeInt(u16, .big), .branch_offset = try input.takeInt(u16, .big),
}; };
} }
}; };
@ -456,7 +456,7 @@ const TableSwitch = struct {
} }
}; };
const Wide = union { const Wide = union(enum) {
form1: struct { form1: struct {
opcode: ModifiableOp, opcode: ModifiableOp,
index: u16, index: u16,
@ -595,8 +595,8 @@ pub const Instruction = union(Op) {
fsub, fsub,
getfield: Index(u16), getfield: Index(u16),
getstatic: Index(u16), getstatic: Index(u16),
goto: Index(u16), goto: Branch(u16),
goto_w: Index(u32), goto_w: Branch(u32),
i2b, i2b,
i2c, i2c,
i2d, i2d,
@ -1045,5 +1045,183 @@ pub const Instruction = union(Op) {
else => {}, else => {},
} }
} }
pub fn indentedFormat(
self: *const Self,
w: *std.Io.Writer,
depth: usize,
indent: u8,
constant_pool: ConstantPool,
) std.Io.Writer.Error!void {
try w.splatByteAll(' ', depth * indent);
try w.print("type: {t}\n", .{ self.* });
switch (self.*) {
.aload, .astore, .dload, .dstore, .fload, .fstore, .iload, .istore, .lload, .lstore => |load_store| {
try w.splatByteAll(' ', depth * indent);
try w.print("index: {d}\n", .{ load_store.index });
},
.anewarray, .checkcast, .instanceof => |constant| {
const @"type" = constant_pool.get(constant.index) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("type:\n");
try @"type".indentedFormat(w, depth, indent + 1, constant_pool);
},
.bipush => |bipush| {
try w.splatByteAll(' ', depth * indent);
try w.print("byte: 0x{X}\n", .{ bipush.byte });
},
.getfield, .getstatic, .putfield, .putstatic => |get_set_field| {
const field = constant_pool.get(get_set_field.index) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("field:\n");
try field.indentedFormat(w, depth, indent + 1, constant_pool);
},
.goto, .if_acmpeq, .if_acmpne, .if_icmpeq, .if_icmpne, .if_icmplt, .if_icmpge, .if_icmpgt, .if_icmple, .ifeq, .ifne, .iflt, .ifge, .ifgt, .ifle, .ifnonnull, .ifnull, .jsr => |branch| {
try w.splatByteAll(' ', depth * indent);
try w.print("branch_offset: {d}\n", .{ branch.branch_offset });
},
.goto_w, .jsr_w => |branch_w| {
try w.splatByteAll(' ', depth * indent);
try w.print("branch_offset: {d}\n", .{ branch_w.branch_offset });
},
.iinc => |iinc| {
try w.splatByteAll(' ', depth * indent);
try w.print("index: {d}\n", .{ iinc.index });
try w.splatByteAll(' ', depth * indent);
try w.print("const: {d}\n", .{ iinc.@"const" });
},
.invokedynamic => |invokedynamic| {
const call_site_specifier = constant_pool.get(invokedynamic.index) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("call_site_specifier:\n");
try call_site_specifier.indentedFormat(w, depth, indent + 1, constant_pool);
},
.invokeinterface => |invokeinterface| {
const interface_method = constant_pool.get(invokeinterface.index) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("interface_method:\n");
try interface_method.indentedFormat(w, depth, indent + 1, constant_pool);
try w.splatByteAll(' ', depth * indent);
try w.print("count: {d}\n", .{ invokeinterface.count });
},
.invokespecial, .invokestatic, .invokevirtual => |invokespecial| {
const method = constant_pool.get(invokespecial.index) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("method:\n");
try method.indentedFormat(w, depth, indent + 1, constant_pool);
},
.ldc => |ldc| {
const value = constant_pool.get(ldc.index) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("value:\n");
try value.indentedFormat(w, depth, indent + 1, constant_pool);
},
.ldc_w, .ldc2_w => |ldc_w| {
const value = constant_pool.get(ldc_w.index) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("value:\n");
try value.indentedFormat(w, depth, indent + 1, constant_pool);
},
.lookupswitch => |lookupswitch| {
try w.splatByteAll(' ', depth * indent);
try w.print("default: {d}\n", .{ lookupswitch.default });
try w.splatByteAll(' ', depth * indent);
_ = try w.write("pairs:\n");
var pairs_indent = indent;
for (lookupswitch.pairs, 0..) |pair, i| {
pairs_indent += 1;
defer pairs_indent -= 1;
try w.splatByteAll(' ', depth * pairs_indent);
try w.print("{d}:\n", .{ i });
{
pairs_indent += 1;
defer pairs_indent -= 1;
try w.splatByteAll(' ', depth * pairs_indent);
try w.print("match: {d}\n", .{ pair.match });
try w.splatByteAll(' ', depth * pairs_indent);
try w.print("offset: {d}\n", .{ pair.offset });
}
}
},
.multianewarray => |multianewarray| {
const @"type" = constant_pool.get(multianewarray.index) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("type:\n");
try @"type".indentedFormat(w, depth, indent + 1, constant_pool);
try w.splatByteAll(' ', depth * indent);
try w.print("dimensions: {d}\n", .{ multianewarray.dimensions });
},
.new => |new| {
const @"type" = constant_pool.get(new.index) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("type:\n");
try @"type".indentedFormat(w, depth, indent + 1, constant_pool);
},
.newarray => |newarray| {
try w.splatByteAll(' ', depth * indent);
try w.print("type: {t}\n", .{ newarray.array_type });
},
.ret => |ret| {
try w.splatByteAll(' ', depth * indent);
try w.print("index: {d}\n", .{ ret.index });
},
.sipush => |sipush| {
try w.splatByteAll(' ', depth * indent);
try w.print("short: 0x{X}\n", .{ sipush.short });
},
.tableswitch => |tableswitch| {
try w.splatByteAll(' ', depth * indent);
try w.print("default: {d}\n", .{ tableswitch.default });
try w.splatByteAll(' ', depth * indent);
_ = try w.write("offsets:\n");
var offsets_indent = indent;
for (tableswitch.offsets, 0..) |offset, i| {
offsets_indent += 1;
defer offsets_indent -= 1;
try w.splatByteAll(' ', depth * offsets_indent);
try w.print("{d}: {d}\n", .{ i, offset });
}
},
.wide => |wide| switch (wide) {
.form1 => |form1| {
try w.splatByteAll(' ', depth * indent);
try w.print("opcode: {t}\n", .{ form1.opcode });
try w.splatByteAll(' ', depth * indent);
try w.print("index: {d}\n", .{ form1.index });
},
.form2 => |form2| {
try w.splatByteAll(' ', depth * indent);
try w.print("opcode: {t}\n", .{ form2.opcode });
try w.splatByteAll(' ', depth * indent);
try w.print("index: {d}\n", .{ form2.index });
try w.splatByteAll(' ', depth * indent);
try w.print("const: {d}\n", .{ form2.@"const" });
},
},
else => {},
}
}
}; };