authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-07-26 16:52:01-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-07-26 16:52:01-07:00
log1aacfa7186187ed467a5e3189a877493d5c620a1
tree62a0292ef77b331055d619c8e05a9de6b6a4bac3
parentf9717f87f55cac0d986b6e3a47eba899a63912fb
parent8e4cc0ce5a21d743bc59def79efa75584d06fee4
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #16538 from kcbanner/fixup_unwind_perf_regression

Reducing compile time regression introduced by the new DWARF unwinder

3 files changed, 278 insertions(+), 205 deletions(-)

lib/std/dwarf.zig+8-8
......@@ -741,7 +741,7 @@ pub const DwarfInfo = struct {
741741 fn scanAllFunctions(di: *DwarfInfo, allocator: mem.Allocator) !void {
742742 var stream = io.fixedBufferStream(di.section(.debug_info).?);
743743 const in = stream.reader();
744 const seekable = &stream.seekableStream();
744 const seekable = stream.seekableStream();
745745 var this_unit_offset: u64 = 0;
746746
747747 var tmp_arena = std.heap.ArenaAllocator.init(allocator);
......@@ -909,8 +909,8 @@ pub const DwarfInfo = struct {
909909
910910 fn scanAllCompileUnits(di: *DwarfInfo, allocator: mem.Allocator) !void {
911911 var stream = io.fixedBufferStream(di.section(.debug_info).?);
912 const in = &stream.reader();
913 const seekable = &stream.seekableStream();
912 const in = stream.reader();
913 const seekable = stream.seekableStream();
914914 var this_unit_offset: u64 = 0;
915915
916916 while (this_unit_offset < try seekable.getEndPos()) {
......@@ -1175,8 +1175,8 @@ pub const DwarfInfo = struct {
11751175
11761176 fn parseAbbrevTable(di: *DwarfInfo, allocator: mem.Allocator, offset: u64) !AbbrevTable {
11771177 var stream = io.fixedBufferStream(di.section(.debug_abbrev).?);
1178 const in = &stream.reader();
1179 const seekable = &stream.seekableStream();
1178 const in = stream.reader();
1179 const seekable = stream.seekableStream();
11801180
11811181 try seekable.seekTo(offset);
11821182 var result = AbbrevTable.init(allocator);
......@@ -1256,8 +1256,8 @@ pub const DwarfInfo = struct {
12561256 target_address: u64,
12571257 ) !debug.LineInfo {
12581258 var stream = io.fixedBufferStream(di.section(.debug_line).?);
1259 const in = &stream.reader();
1260 const seekable = &stream.seekableStream();
1259 const in = stream.reader();
1260 const seekable = stream.seekableStream();
12611261
12621262 const compile_unit_cwd = try compile_unit.die.getAttrString(di, AT.comp_dir, di.section(.debug_line_str), compile_unit);
12631263 const line_info_offset = try compile_unit.die.getAttrSecOffset(AT.stmt_list);
......@@ -1638,7 +1638,7 @@ pub const DwarfInfo = struct {
16381638 }
16391639 }
16401640
1641 std.mem.sort(FrameDescriptionEntry, di.fde_list.items, {}, struct {
1641 std.mem.sortUnstable(FrameDescriptionEntry, di.fde_list.items, {}, struct {
16421642 fn lessThan(ctx: void, a: FrameDescriptionEntry, b: FrameDescriptionEntry) bool {
16431643 _ = ctx;
16441644 return a.pc_begin < b.pc_begin;
lib/std/dwarf/call_frame.zig+256-182
......@@ -50,176 +50,250 @@ const Opcode = enum(u8) {
5050 pub const hi_user = 0x3f;
5151};
5252
53const Operand = enum {
54 opcode_delta,
55 opcode_register,
56 uleb128_register,
57 uleb128_offset,
58 sleb128_offset,
59 address,
60 u8_delta,
61 u16_delta,
62 u32_delta,
63 block,
64
65 fn Storage(comptime self: Operand) type {
66 return switch (self) {
67 .opcode_delta, .opcode_register => u8,
68 .uleb128_register => u8,
69 .uleb128_offset => u64,
70 .sleb128_offset => i64,
71 .address => u64,
72 .u8_delta => u8,
73 .u16_delta => u16,
74 .u32_delta => u32,
75 .block => []const u8,
76 };
77 }
53fn readBlock(stream: *std.io.FixedBufferStream([]const u8)) ![]const u8 {
54 const reader = stream.reader();
55 const block_len = try leb.readULEB128(usize, reader);
56 if (stream.pos + block_len > stream.buffer.len) return error.InvalidOperand;
7857
79 fn read(
80 comptime self: Operand,
81 stream: *std.io.FixedBufferStream([]const u8),
82 opcode_value: ?u6,
83 addr_size_bytes: u8,
84 endian: std.builtin.Endian,
85 ) !Storage(self) {
86 const reader = stream.reader();
87 return switch (self) {
88 .opcode_delta, .opcode_register => opcode_value orelse return error.InvalidOperand,
89 .uleb128_register => try leb.readULEB128(u8, reader),
90 .uleb128_offset => try leb.readULEB128(u64, reader),
91 .sleb128_offset => try leb.readILEB128(i64, reader),
92 .address => switch (addr_size_bytes) {
93 2 => try reader.readInt(u16, endian),
94 4 => try reader.readInt(u32, endian),
95 8 => try reader.readInt(u64, endian),
96 else => return error.InvalidAddrSize,
97 },
98 .u8_delta => try reader.readByte(),
99 .u16_delta => try reader.readInt(u16, endian),
100 .u32_delta => try reader.readInt(u32, endian),
101 .block => {
102 const block_len = try leb.readULEB128(usize, reader);
103 if (stream.pos + block_len > stream.buffer.len) return error.InvalidOperand;
104
105 const block = stream.buffer[stream.pos..][0..block_len];
106 reader.context.pos += block_len;
107
108 return block;
109 },
110 };
111 }
112};
58 const block = stream.buffer[stream.pos..][0..block_len];
59 reader.context.pos += block_len;
11360
114fn InstructionType(comptime definition: anytype) type {
115 const definition_type = @typeInfo(@TypeOf(definition));
116 assert(definition_type == .Struct);
117
118 const definition_len = definition_type.Struct.fields.len;
119 comptime var fields: [definition_len]std.builtin.Type.StructField = undefined;
120 inline for (definition_type.Struct.fields, &fields) |definition_field, *operands_field| {
121 const opcode = std.enums.nameCast(Operand, @field(definition, definition_field.name));
122 const storage_type = opcode.Storage();
123 operands_field.* = .{
124 .name = definition_field.name,
125 .type = storage_type,
126 .default_value = null,
127 .is_comptime = false,
128 .alignment = @alignOf(storage_type),
129 };
130 }
131
132 const InstructionOperands = @Type(.{
133 .Struct = .{
134 .layout = .Auto,
135 .fields = &fields,
136 .decls = &.{},
137 .is_tuple = false,
138 },
139 });
140
141 return struct {
142 const Self = @This();
143 operands: InstructionOperands,
144
145 pub fn read(
146 stream: *std.io.FixedBufferStream([]const u8),
147 opcode_value: ?u6,
148 addr_size_bytes: u8,
149 endian: std.builtin.Endian,
150 ) !Self {
151 var operands: InstructionOperands = undefined;
152 inline for (definition_type.Struct.fields) |definition_field| {
153 const operand = comptime std.enums.nameCast(Operand, @field(definition, definition_field.name));
154 @field(operands, definition_field.name) = try operand.read(stream, opcode_value, addr_size_bytes, endian);
155 }
156
157 return .{ .operands = operands };
158 }
159 };
61 return block;
16062}
16163
16264pub const Instruction = union(Opcode) {
163 advance_loc: InstructionType(.{ .delta = .opcode_delta }),
164 offset: InstructionType(.{ .register = .opcode_register, .offset = .uleb128_offset }),
165 offset_extended: InstructionType(.{ .register = .uleb128_register, .offset = .uleb128_offset }),
166 restore: InstructionType(.{ .register = .opcode_register }),
167 restore_extended: InstructionType(.{ .register = .uleb128_register }),
168 nop: InstructionType(.{}),
169 set_loc: InstructionType(.{ .address = .address }),
170 advance_loc1: InstructionType(.{ .delta = .u8_delta }),
171 advance_loc2: InstructionType(.{ .delta = .u16_delta }),
172 advance_loc4: InstructionType(.{ .delta = .u32_delta }),
173 undefined: InstructionType(.{ .register = .uleb128_register }),
174 same_value: InstructionType(.{ .register = .uleb128_register }),
175 register: InstructionType(.{ .register = .uleb128_register, .target_register = .uleb128_register }),
176 remember_state: InstructionType(.{}),
177 restore_state: InstructionType(.{}),
178 def_cfa: InstructionType(.{ .register = .uleb128_register, .offset = .uleb128_offset }),
179 def_cfa_register: InstructionType(.{ .register = .uleb128_register }),
180 def_cfa_offset: InstructionType(.{ .offset = .uleb128_offset }),
181 def_cfa_expression: InstructionType(.{ .block = .block }),
182 expression: InstructionType(.{ .register = .uleb128_register, .block = .block }),
183 offset_extended_sf: InstructionType(.{ .register = .uleb128_register, .offset = .sleb128_offset }),
184 def_cfa_sf: InstructionType(.{ .register = .uleb128_register, .offset = .sleb128_offset }),
185 def_cfa_offset_sf: InstructionType(.{ .offset = .sleb128_offset }),
186 val_offset: InstructionType(.{ .register = .uleb128_register, .offset = .uleb128_offset }),
187 val_offset_sf: InstructionType(.{ .register = .uleb128_register, .offset = .sleb128_offset }),
188 val_expression: InstructionType(.{ .register = .uleb128_register, .block = .block }),
189
190 fn readOperands(
191 self: *Instruction,
192 stream: *std.io.FixedBufferStream([]const u8),
193 opcode_value: ?u6,
194 addr_size_bytes: u8,
195 endian: std.builtin.Endian,
196 ) !void {
197 switch (self.*) {
198 inline else => |*inst| inst.* = try @TypeOf(inst.*).read(stream, opcode_value, addr_size_bytes, endian),
199 }
200 }
65 advance_loc: struct {
66 delta: u8,
67 },
68 offset: struct {
69 register: u8,
70 offset: u64,
71 },
72 offset_extended: struct {
73 register: u8,
74 offset: u64,
75 },
76 restore: struct {
77 register: u8,
78 },
79 restore_extended: struct {
80 register: u8,
81 },
82 nop: void,
83 set_loc: struct {
84 address: u64,
85 },
86 advance_loc1: struct {
87 delta: u8,
88 },
89 advance_loc2: struct {
90 delta: u16,
91 },
92 advance_loc4: struct {
93 delta: u32,
94 },
95 undefined: struct {
96 register: u8,
97 },
98 same_value: struct {
99 register: u8,
100 },
101 register: struct {
102 register: u8,
103 target_register: u8,
104 },
105 remember_state: void,
106 restore_state: void,
107 def_cfa: struct {
108 register: u8,
109 offset: u64,
110 },
111 def_cfa_register: struct {
112 register: u8,
113 },
114 def_cfa_offset: struct {
115 offset: u64,
116 },
117 def_cfa_expression: struct {
118 block: []const u8,
119 },
120 expression: struct {
121 register: u8,
122 block: []const u8,
123 },
124 offset_extended_sf: struct {
125 register: u8,
126 offset: i64,
127 },
128 def_cfa_sf: struct {
129 register: u8,
130 offset: i64,
131 },
132 def_cfa_offset_sf: struct {
133 offset: i64,
134 },
135 val_offset: struct {
136 register: u8,
137 offset: u64,
138 },
139 val_offset_sf: struct {
140 register: u8,
141 offset: i64,
142 },
143 val_expression: struct {
144 register: u8,
145 block: []const u8,
146 },
201147
202148 pub fn read(
203149 stream: *std.io.FixedBufferStream([]const u8),
204150 addr_size_bytes: u8,
205151 endian: std.builtin.Endian,
206152 ) !Instruction {
207 return switch (try stream.reader().readByte()) {
208 inline Opcode.lo_inline...Opcode.hi_inline => |opcode| blk: {
153 const reader = stream.reader();
154 switch (try reader.readByte()) {
155 Opcode.lo_inline...Opcode.hi_inline => |opcode| {
209156 const e: Opcode = @enumFromInt(opcode & 0b11000000);
210 var result = @unionInit(Instruction, @tagName(e), undefined);
211 try result.readOperands(stream, @as(u6, @intCast(opcode & 0b111111)), addr_size_bytes, endian);
212 break :blk result;
157 const value: u6 = @intCast(opcode & 0b111111);
158 return switch (e) {
159 .advance_loc => .{
160 .advance_loc = .{ .delta = value },
161 },
162 .offset => .{
163 .offset = .{
164 .register = value,
165 .offset = try leb.readULEB128(u64, reader),
166 },
167 },
168 .restore => .{
169 .restore = .{ .register = value },
170 },
171 else => unreachable,
172 };
213173 },
214 inline Opcode.lo_reserved...Opcode.hi_reserved => |opcode| blk: {
174 Opcode.lo_reserved...Opcode.hi_reserved => |opcode| {
215175 const e: Opcode = @enumFromInt(opcode);
216 var result = @unionInit(Instruction, @tagName(e), undefined);
217 try result.readOperands(stream, null, addr_size_bytes, endian);
218 break :blk result;
176 return switch (e) {
177 .advance_loc,
178 .offset,
179 .restore,
180 => unreachable,
181 .nop => .{ .nop = {} },
182 .set_loc => .{
183 .set_loc = .{
184 .address = switch (addr_size_bytes) {
185 2 => try reader.readInt(u16, endian),
186 4 => try reader.readInt(u32, endian),
187 8 => try reader.readInt(u64, endian),
188 else => return error.InvalidAddrSize,
189 },
190 },
191 },
192 .advance_loc1 => .{
193 .advance_loc1 = .{ .delta = try reader.readByte() },
194 },
195 .advance_loc2 => .{
196 .advance_loc2 = .{ .delta = try reader.readInt(u16, endian) },
197 },
198 .advance_loc4 => .{
199 .advance_loc4 = .{ .delta = try reader.readInt(u32, endian) },
200 },
201 .offset_extended => .{
202 .offset_extended = .{
203 .register = try leb.readULEB128(u8, reader),
204 .offset = try leb.readULEB128(u64, reader),
205 },
206 },
207 .restore_extended => .{
208 .restore_extended = .{
209 .register = try leb.readULEB128(u8, reader),
210 },
211 },
212 .undefined => .{
213 .undefined = .{
214 .register = try leb.readULEB128(u8, reader),
215 },
216 },
217 .same_value => .{
218 .same_value = .{
219 .register = try leb.readULEB128(u8, reader),
220 },
221 },
222 .register => .{
223 .register = .{
224 .register = try leb.readULEB128(u8, reader),
225 .target_register = try leb.readULEB128(u8, reader),
226 },
227 },
228 .remember_state => .{ .remember_state = {} },
229 .restore_state => .{ .restore_state = {} },
230 .def_cfa => .{
231 .def_cfa = .{
232 .register = try leb.readULEB128(u8, reader),
233 .offset = try leb.readULEB128(u64, reader),
234 },
235 },
236 .def_cfa_register => .{
237 .def_cfa_register = .{
238 .register = try leb.readULEB128(u8, reader),
239 },
240 },
241 .def_cfa_offset => .{
242 .def_cfa_offset = .{
243 .offset = try leb.readULEB128(u64, reader),
244 },
245 },
246 .def_cfa_expression => .{
247 .def_cfa_expression = .{
248 .block = try readBlock(stream),
249 },
250 },
251 .expression => .{
252 .expression = .{
253 .register = try leb.readULEB128(u8, reader),
254 .block = try readBlock(stream),
255 },
256 },
257 .offset_extended_sf => .{
258 .offset_extended_sf = .{
259 .register = try leb.readULEB128(u8, reader),
260 .offset = try leb.readILEB128(i64, reader),
261 },
262 },
263 .def_cfa_sf => .{
264 .def_cfa_sf = .{
265 .register = try leb.readULEB128(u8, reader),
266 .offset = try leb.readILEB128(i64, reader),
267 },
268 },
269 .def_cfa_offset_sf => .{
270 .def_cfa_offset_sf = .{
271 .offset = try leb.readILEB128(i64, reader),
272 },
273 },
274 .val_offset => .{
275 .val_offset = .{
276 .register = try leb.readULEB128(u8, reader),
277 .offset = try leb.readULEB128(u64, reader),
278 },
279 },
280 .val_offset_sf => .{
281 .val_offset_sf = .{
282 .register = try leb.readULEB128(u8, reader),
283 .offset = try leb.readILEB128(i64, reader),
284 },
285 },
286 .val_expression => .{
287 .val_expression = .{
288 .register = try leb.readULEB128(u8, reader),
289 .block = try readBlock(stream),
290 },
291 },
292 };
219293 },
220 Opcode.lo_user...Opcode.hi_user => error.UnimplementedUserOpcode,
221 else => error.InvalidOpcode,
222 };
294 Opcode.lo_user...Opcode.hi_user => return error.UnimplementedUserOpcode,
295 else => return error.InvalidOpcode,
296 }
223297 }
224298};
225299
......@@ -475,16 +549,16 @@ pub const VirtualMachine = struct {
475549 const prev_row = self.current_row;
476550 switch (instruction) {
477551 .set_loc => |i| {
478 if (i.operands.address <= self.current_row.offset) return error.InvalidOperation;
552 if (i.address <= self.current_row.offset) return error.InvalidOperation;
479553 // TODO: Check cie.segment_selector_size != 0 for DWARFV4
480 self.current_row.offset = i.operands.address;
554 self.current_row.offset = i.address;
481555 },
482556 inline .advance_loc,
483557 .advance_loc1,
484558 .advance_loc2,
485559 .advance_loc4,
486560 => |i| {
487 self.current_row.offset += i.operands.delta * cie.code_alignment_factor;
561 self.current_row.offset += i.delta * cie.code_alignment_factor;
488562 self.current_row.copy_on_write = true;
489563 },
490564 inline .offset,
......@@ -492,35 +566,35 @@ pub const VirtualMachine = struct {
492566 .offset_extended_sf,
493567 => |i| {
494568 try self.resolveCopyOnWrite(allocator);
495 const column = try self.getOrAddColumn(allocator, i.operands.register);
496 column.rule = .{ .offset = @as(i64, @intCast(i.operands.offset)) * cie.data_alignment_factor };
569 const column = try self.getOrAddColumn(allocator, i.register);
570 column.rule = .{ .offset = @as(i64, @intCast(i.offset)) * cie.data_alignment_factor };
497571 },
498572 inline .restore,
499573 .restore_extended,
500574 => |i| {
501575 try self.resolveCopyOnWrite(allocator);
502576 if (self.cie_row) |cie_row| {
503 const column = try self.getOrAddColumn(allocator, i.operands.register);
577 const column = try self.getOrAddColumn(allocator, i.register);
504578 column.rule = for (self.rowColumns(cie_row)) |cie_column| {
505 if (cie_column.register == i.operands.register) break cie_column.rule;
579 if (cie_column.register == i.register) break cie_column.rule;
506580 } else .{ .default = {} };
507581 } else return error.InvalidOperation;
508582 },
509583 .nop => {},
510584 .undefined => |i| {
511585 try self.resolveCopyOnWrite(allocator);
512 const column = try self.getOrAddColumn(allocator, i.operands.register);
586 const column = try self.getOrAddColumn(allocator, i.register);
513587 column.rule = .{ .undefined = {} };
514588 },
515589 .same_value => |i| {
516590 try self.resolveCopyOnWrite(allocator);
517 const column = try self.getOrAddColumn(allocator, i.operands.register);
591 const column = try self.getOrAddColumn(allocator, i.register);
518592 column.rule = .{ .same_value = {} };
519593 },
520594 .register => |i| {
521595 try self.resolveCopyOnWrite(allocator);
522 const column = try self.getOrAddColumn(allocator, i.operands.register);
523 column.rule = .{ .register = i.operands.target_register };
596 const column = try self.getOrAddColumn(allocator, i.register);
597 column.rule = .{ .register = i.target_register };
524598 },
525599 .remember_state => {
526600 try self.stack.append(allocator, self.current_row.columns);
......@@ -538,69 +612,69 @@ pub const VirtualMachine = struct {
538612 .def_cfa => |i| {
539613 try self.resolveCopyOnWrite(allocator);
540614 self.current_row.cfa = .{
541 .register = i.operands.register,
542 .rule = .{ .val_offset = @intCast(i.operands.offset) },
615 .register = i.register,
616 .rule = .{ .val_offset = @intCast(i.offset) },
543617 };
544618 },
545619 .def_cfa_sf => |i| {
546620 try self.resolveCopyOnWrite(allocator);
547621 self.current_row.cfa = .{
548 .register = i.operands.register,
549 .rule = .{ .val_offset = i.operands.offset * cie.data_alignment_factor },
622 .register = i.register,
623 .rule = .{ .val_offset = i.offset * cie.data_alignment_factor },
550624 };
551625 },
552626 .def_cfa_register => |i| {
553627 try self.resolveCopyOnWrite(allocator);
554628 if (self.current_row.cfa.register == null or self.current_row.cfa.rule != .val_offset) return error.InvalidOperation;
555 self.current_row.cfa.register = i.operands.register;
629 self.current_row.cfa.register = i.register;
556630 },
557631 .def_cfa_offset => |i| {
558632 try self.resolveCopyOnWrite(allocator);
559633 if (self.current_row.cfa.register == null or self.current_row.cfa.rule != .val_offset) return error.InvalidOperation;
560634 self.current_row.cfa.rule = .{
561 .val_offset = @intCast(i.operands.offset),
635 .val_offset = @intCast(i.offset),
562636 };
563637 },
564638 .def_cfa_offset_sf => |i| {
565639 try self.resolveCopyOnWrite(allocator);
566640 if (self.current_row.cfa.register == null or self.current_row.cfa.rule != .val_offset) return error.InvalidOperation;
567641 self.current_row.cfa.rule = .{
568 .val_offset = i.operands.offset * cie.data_alignment_factor,
642 .val_offset = i.offset * cie.data_alignment_factor,
569643 };
570644 },
571645 .def_cfa_expression => |i| {
572646 try self.resolveCopyOnWrite(allocator);
573647 self.current_row.cfa.register = undefined;
574648 self.current_row.cfa.rule = .{
575 .expression = i.operands.block,
649 .expression = i.block,
576650 };
577651 },
578652 .expression => |i| {
579653 try self.resolveCopyOnWrite(allocator);
580 const column = try self.getOrAddColumn(allocator, i.operands.register);
654 const column = try self.getOrAddColumn(allocator, i.register);
581655 column.rule = .{
582 .expression = i.operands.block,
656 .expression = i.block,
583657 };
584658 },
585659 .val_offset => |i| {
586660 try self.resolveCopyOnWrite(allocator);
587 const column = try self.getOrAddColumn(allocator, i.operands.register);
661 const column = try self.getOrAddColumn(allocator, i.register);
588662 column.rule = .{
589 .val_offset = @as(i64, @intCast(i.operands.offset)) * cie.data_alignment_factor,
663 .val_offset = @as(i64, @intCast(i.offset)) * cie.data_alignment_factor,
590664 };
591665 },
592666 .val_offset_sf => |i| {
593667 try self.resolveCopyOnWrite(allocator);
594 const column = try self.getOrAddColumn(allocator, i.operands.register);
668 const column = try self.getOrAddColumn(allocator, i.register);
595669 column.rule = .{
596 .val_offset = i.operands.offset * cie.data_alignment_factor,
670 .val_offset = i.offset * cie.data_alignment_factor,
597671 };
598672 },
599673 .val_expression => |i| {
600674 try self.resolveCopyOnWrite(allocator);
601 const column = try self.getOrAddColumn(allocator, i.operands.register);
675 const column = try self.getOrAddColumn(allocator, i.register);
602676 column.rule = .{
603 .val_expression = i.operands.block,
677 .val_expression = i.block,
604678 };
605679 },
606680 }
lib/std/dwarf/expressions.zig+14-15
......@@ -318,6 +318,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
318318
319319 const opcode = try stream.reader().readByte();
320320 if (options.call_frame_context and !isOpcodeValidInCFA(opcode)) return error.InvalidCFAOpcode;
321 const operand = try readOperand(stream, opcode, context);
321322 switch (opcode) {
322323
323324 // 2.5.1.1: Literal Encodings
......@@ -333,10 +334,10 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
333334 OP.const8s,
334335 OP.constu,
335336 OP.consts,
336 => try self.stack.append(allocator, .{ .generic = (try readOperand(stream, opcode, context)).?.generic }),
337 => try self.stack.append(allocator, .{ .generic = operand.?.generic }),
337338
338339 OP.const_type => {
339 const const_type = (try readOperand(stream, opcode, context)).?.const_type;
340 const const_type = operand.?.const_type;
340341 try self.stack.append(allocator, .{ .const_type = .{
341342 .type_offset = const_type.type_offset,
342343 .value_bytes = const_type.value_bytes,
......@@ -348,7 +349,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
348349 => {
349350 if (context.compile_unit == null) return error.IncompleteExpressionContext;
350351 if (context.debug_addr == null) return error.IncompleteExpressionContext;
351 const debug_addr_index = (try readOperand(stream, opcode, context)).?.generic;
352 const debug_addr_index = operand.?.generic;
352353 const offset = context.compile_unit.?.addr_base + debug_addr_index;
353354 if (offset >= context.debug_addr.?.len) return error.InvalidExpression;
354355 const value = mem.readIntSliceNative(usize, context.debug_addr.?[offset..][0..@sizeOf(usize)]);
......@@ -360,7 +361,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
360361 if (context.compile_unit == null) return error.IncompleteExpressionContext;
361362 if (context.compile_unit.?.frame_base == null) return error.IncompleteExpressionContext;
362363
363 const offset: i64 = @intCast((try readOperand(stream, opcode, context)).?.generic);
364 const offset: i64 = @intCast(operand.?.generic);
364365 _ = offset;
365366
366367 switch (context.compile_unit.?.frame_base.?.*) {
......@@ -384,7 +385,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
384385 => {
385386 if (context.thread_context == null) return error.IncompleteExpressionContext;
386387
387 const base_register = (try readOperand(stream, opcode, context)).?.base_register;
388 const base_register = operand.?.base_register;
388389 var value: i64 = @intCast(mem.readIntSliceNative(usize, try abi.regBytes(
389390 context.thread_context.?,
390391 base_register.base_register,
......@@ -394,7 +395,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
394395 try self.stack.append(allocator, .{ .generic = @intCast(value) });
395396 },
396397 OP.regval_type => {
397 const register_type = (try readOperand(stream, opcode, context)).?.register_type;
398 const register_type = operand.?.register_type;
398399 const value = mem.readIntSliceNative(usize, try abi.regBytes(
399400 context.thread_context.?,
400401 register_type.register,
......@@ -418,7 +419,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
418419 _ = self.stack.pop();
419420 },
420421 OP.pick, OP.over => {
421 const stack_index = if (opcode == OP.over) 1 else (try readOperand(stream, opcode, context)).?.generic;
422 const stack_index = if (opcode == OP.over) 1 else operand.?.generic;
422423 if (stack_index >= self.stack.items.len) return error.InvalidExpression;
423424 try self.stack.append(allocator, self.stack.items[self.stack.items.len - 1 - stack_index]);
424425 },
......@@ -459,8 +460,6 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
459460 _ = addr_space_identifier;
460461
461462 if (context.isValidMemory) |isValidMemory| if (!isValidMemory(addr)) return error.InvalidExpression;
462
463 const operand = try readOperand(stream, opcode, context);
464463 const size = switch (opcode) {
465464 OP.deref,
466465 OP.xderef,
......@@ -594,7 +593,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
594593 },
595594 OP.plus_uconst => {
596595 if (self.stack.items.len == 0) return error.InvalidExpression;
597 const constant = (try readOperand(stream, opcode, context)).?.generic;
596 const constant = operand.?.generic;
598597 self.stack.items[self.stack.items.len - 1] = .{
599598 .generic = try std.math.add(addr_type, try self.stack.items[self.stack.items.len - 1].asIntegral(), constant),
600599 };
......@@ -663,7 +662,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
663662 }
664663 },
665664 OP.skip, OP.bra => {
666 const branch_offset = (try readOperand(stream, opcode, context)).?.branch_offset;
665 const branch_offset = operand.?.branch_offset;
667666 const condition = if (opcode == OP.bra) blk: {
668667 if (self.stack.items.len == 0) return error.InvalidExpression;
669668 break :blk try self.stack.pop().asIntegral() != 0;
......@@ -683,7 +682,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
683682 OP.call4,
684683 OP.call_ref,
685684 => {
686 const debug_info_offset = (try readOperand(stream, opcode, context)).?.generic;
685 const debug_info_offset = operand.?.generic;
687686 _ = debug_info_offset;
688687
689688 // TODO: Load a DIE entry at debug_info_offset in a .debug_info section (the spec says that it
......@@ -696,7 +695,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
696695 // 2.5.1.6: Type Conversions
697696 OP.convert => {
698697 if (self.stack.items.len == 0) return error.InvalidExpression;
699 const type_offset = (try readOperand(stream, opcode, context)).?.generic;
698 const type_offset = operand.?.generic;
700699
701700 // TODO: Load the DW_TAG_base_type entries in context.compile_unit and verify both types are the same size
702701 const value = self.stack.items[self.stack.items.len - 1];
......@@ -710,7 +709,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
710709 },
711710 OP.reinterpret => {
712711 if (self.stack.items.len == 0) return error.InvalidExpression;
713 const type_offset = (try readOperand(stream, opcode, context)).?.generic;
712 const type_offset = operand.?.generic;
714713
715714 // TODO: Load the DW_TAG_base_type entries in context.compile_unit and verify both types are the same size
716715 const value = self.stack.items[self.stack.items.len - 1];
......@@ -745,7 +744,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
745744 // 2.5.1.7: Special Operations
746745 OP.nop => {},
747746 OP.entry_value => {
748 const block = (try readOperand(stream, opcode, context)).?.block;
747 const block = operand.?.block;
749748 if (block.len == 0) return error.InvalidSubExpression;
750749
751750 // TODO: The spec states that this sub-expression needs to observe the state (ie. registers)