| ... | @@ -3,18 +3,13 @@ const debug = std.debug; | ... | @@ -3,18 +3,13 @@ const debug = std.debug; |
| 3 | const leb = @import("../leb128.zig"); | 3 | const leb = @import("../leb128.zig"); |
| 4 | const abi = @import("abi.zig"); | 4 | const abi = @import("abi.zig"); |
| 5 | const dwarf = @import("../dwarf.zig"); | 5 | const dwarf = @import("../dwarf.zig"); |
| | 6 | const expressions = @import("expressions.zig"); |
| 6 | | 7 | |
| 7 | // These enum values correspond to the opcode encoding itself, with | | |
| 8 | // the exception of the opcodes that include data in the opcode itself. | | |
| 9 | // For those, the enum value is the opcode with the lower 6 bits (the data) masked to 0. | | |
| 10 | const Opcode = enum(u8) { | 8 | const Opcode = enum(u8) { |
| 11 | // These are placeholders that define the range of vendor-specific opcodes | | |
| 12 | const lo_user = 0x1c; | | |
| 13 | const hi_user = 0x3f; | | |
| 14 | | | |
| 15 | advance_loc = 0x1 << 6, | 9 | advance_loc = 0x1 << 6, |
| 16 | offset = 0x2 << 6, | 10 | offset = 0x2 << 6, |
| 17 | restore = 0x3 << 6, | 11 | restore = 0x3 << 6, |
| | 12 | |
| 18 | nop = 0x00, | 13 | nop = 0x00, |
| 19 | set_loc = 0x01, | 14 | set_loc = 0x01, |
| 20 | advance_loc1 = 0x02, | 15 | advance_loc1 = 0x02, |
| ... | @@ -39,7 +34,17 @@ const Opcode = enum(u8) { | ... | @@ -39,7 +34,17 @@ const Opcode = enum(u8) { |
| 39 | val_offset_sf = 0x15, | 34 | val_offset_sf = 0x15, |
| 40 | val_expression = 0x16, | 35 | val_expression = 0x16, |
| 41 | | 36 | |
| 42 | _, | 37 | // These opcodes encode an operand in the lower 6 bits of the opcode itself |
| | 38 | pub const lo_inline = Opcode.advance_loc; |
| | 39 | pub const hi_inline = Opcode.restore; |
| | 40 | |
| | 41 | // These opcodes are trailed by zero or more operands |
| | 42 | pub const lo_reserved = Opcode.nop; |
| | 43 | pub const hi_reserved = Opcode.val_expression; |
| | 44 | |
| | 45 | // Vendor-specific opcodes |
| | 46 | pub const lo_user = 0x1c; |
| | 47 | pub const hi_user = 0x3f; |
| 43 | }; | 48 | }; |
| 44 | | 49 | |
| 45 | const Operand = enum { | 50 | const Operand = enum { |
| ... | @@ -70,11 +75,12 @@ const Operand = enum { | ... | @@ -70,11 +75,12 @@ const Operand = enum { |
| 70 | | 75 | |
| 71 | fn read( | 76 | fn read( |
| 72 | comptime self: Operand, | 77 | comptime self: Operand, |
| 73 | reader: anytype, | 78 | stream: *std.io.FixedBufferStream([]const u8), |
| 74 | opcode_value: ?u6, | 79 | opcode_value: ?u6, |
| 75 | addr_size_bytes: u8, | 80 | addr_size_bytes: u8, |
| 76 | endian: std.builtin.Endian, | 81 | endian: std.builtin.Endian, |
| 77 | ) !Storage(self) { | 82 | ) !Storage(self) { |
| | 83 | const reader = stream.reader(); |
| 78 | return switch (self) { | 84 | return switch (self) { |
| 79 | .opcode_delta, .opcode_register => opcode_value orelse return error.InvalidOperand, | 85 | .opcode_delta, .opcode_register => opcode_value orelse return error.InvalidOperand, |
| 80 | .uleb128_register => try leb.readULEB128(u8, reader), | 86 | .uleb128_register => try leb.readULEB128(u8, reader), |
| ... | @@ -91,13 +97,13 @@ const Operand = enum { | ... | @@ -91,13 +97,13 @@ const Operand = enum { |
| 91 | .u32_delta => try reader.readInt(u32, endian), | 97 | .u32_delta => try reader.readInt(u32, endian), |
| 92 | .block => { | 98 | .block => { |
| 93 | const block_len = try leb.readULEB128(u64, reader); | 99 | const block_len = try leb.readULEB128(u64, reader); |
| | 100 | if (stream.pos + block_len > stream.buffer.len) return error.InvalidOperand; |
| 94 | | 101 | |
| 95 | // TODO: This feels like a kludge, change to FixedBufferStream param? | 102 | const block = stream.buffer[stream.pos..][0..block_len]; |
| 96 | const block = reader.context.buffer[reader.context.pos..][0..block_len]; | | |
| 97 | reader.context.pos += block_len; | 103 | reader.context.pos += block_len; |
| 98 | | 104 | |
| 99 | return block; | 105 | return block; |
| 100 | } | 106 | }, |
| 101 | }; | 107 | }; |
| 102 | } | 108 | } |
| 103 | }; | 109 | }; |
| ... | @@ -133,11 +139,16 @@ fn InstructionType(comptime definition: anytype) type { | ... | @@ -133,11 +139,16 @@ fn InstructionType(comptime definition: anytype) type { |
| 133 | const Self = @This(); | 139 | const Self = @This(); |
| 134 | operands: InstructionOperands, | 140 | operands: InstructionOperands, |
| 135 | | 141 | |
| 136 | pub fn read(reader: anytype, opcode_value: ?u6, addr_size_bytes: u8, endian: std.builtin.Endian) !Self { | 142 | pub fn read( |
| | 143 | stream: *std.io.FixedBufferStream([]const u8), |
| | 144 | opcode_value: ?u6, |
| | 145 | addr_size_bytes: u8, |
| | 146 | endian: std.builtin.Endian, |
| | 147 | ) !Self { |
| 137 | var operands: InstructionOperands = undefined; | 148 | var operands: InstructionOperands = undefined; |
| 138 | inline for (definition_type.Struct.fields) |definition_field| { | 149 | inline for (definition_type.Struct.fields) |definition_field| { |
| 139 | const operand = comptime std.enums.nameCast(Operand, @field(definition, definition_field.name)); | 150 | const operand = comptime std.enums.nameCast(Operand, @field(definition, definition_field.name)); |
| 140 | @field(operands, definition_field.name) = try operand.read(reader, opcode_value, addr_size_bytes, endian); | 151 | @field(operands, definition_field.name) = try operand.read(stream, opcode_value, addr_size_bytes, endian); |
| 141 | } | 152 | } |
| 142 | | 153 | |
| 143 | return .{ .operands = operands }; | 154 | return .{ .operands = operands }; |
| ... | @@ -173,37 +184,44 @@ pub const Instruction = union(Opcode) { | ... | @@ -173,37 +184,44 @@ pub const Instruction = union(Opcode) { |
| 173 | val_offset_sf: InstructionType(.{ .a = .uleb128_offset, .b = .sleb128_offset }), | 184 | val_offset_sf: InstructionType(.{ .a = .uleb128_offset, .b = .sleb128_offset }), |
| 174 | val_expression: InstructionType(.{ .a = .uleb128_offset, .block = .block }), | 185 | val_expression: InstructionType(.{ .a = .uleb128_offset, .block = .block }), |
| 175 | | 186 | |
| 176 | pub fn read(reader: anytype, addr_size_bytes: u8, endian: std.builtin.Endian) !Instruction { | 187 | pub fn read( |
| 177 | const opcode = try reader.readByte(); | 188 | stream: *std.io.FixedBufferStream([]const u8), |
| 178 | const upper = opcode & 0b11000000; | 189 | addr_size_bytes: u8, |
| 179 | return switch (upper) { | 190 | endian: std.builtin.Endian, |
| 180 | inline @enumToInt(Opcode.advance_loc), @enumToInt(Opcode.offset), @enumToInt(Opcode.restore) => |u| @unionInit( | 191 | ) !Instruction { |
| 181 | Instruction, | 192 | @setEvalBranchQuota(1800); |
| 182 | @tagName(@intToEnum(Opcode, u)), | 193 | |
| 183 | try std.meta.TagPayload(Instruction, @intToEnum(Opcode, u)).read(reader, @intCast(u6, opcode & 0b111111), addr_size_bytes, endian), | 194 | return switch (try stream.reader().readByte()) { |
| 184 | ), | 195 | inline @enumToInt(Opcode.lo_inline)...@enumToInt(Opcode.hi_inline) => |opcode| blk: { |
| 185 | 0 => blk: { | 196 | const e = @intToEnum(Opcode, opcode & 0b11000000); |
| 186 | inline for (@typeInfo(Opcode).Enum.fields) |field| { | 197 | const payload_type = std.meta.TagPayload(Instruction, e); |
| 187 | if (field.value == opcode) { | 198 | const value = try payload_type.read(stream, @intCast(u6, opcode & 0b111111), addr_size_bytes, endian); |
| 188 | break :blk @unionInit( | 199 | break :blk @unionInit(Instruction, @tagName(e), value); |
| 189 | Instruction, | | |
| 190 | @tagName(@intToEnum(Opcode, field.value)), | | |
| 191 | try std.meta.TagPayload(Instruction, @intToEnum(Opcode, field.value)).read(reader, null, addr_size_bytes, endian), | | |
| 192 | ); | | |
| 193 | } | | |
| 194 | } | | |
| 195 | break :blk error.UnknownOpcode; | | |
| 196 | }, | 200 | }, |
| 197 | else => error.UnknownOpcode, | 201 | inline @enumToInt(Opcode.lo_reserved)...@enumToInt(Opcode.hi_reserved) => |opcode| blk: { |
| | 202 | const e = @intToEnum(Opcode, opcode); |
| | 203 | const payload_type = std.meta.TagPayload(Instruction, e); |
| | 204 | const value = try payload_type.read(stream, null, addr_size_bytes, endian); |
| | 205 | break :blk @unionInit(Instruction, @tagName(e), value); |
| | 206 | }, |
| | 207 | Opcode.lo_user...Opcode.hi_user => error.UnimplementedUserOpcode, |
| | 208 | else => error.InvalidOpcode, |
| 198 | }; | 209 | }; |
| 199 | } | 210 | } |
| 200 | | 211 | |
| 201 | pub fn writeOperands(self: Instruction, writer: anytype, cie: dwarf.CommonInformationEntry, arch: ?std.Target.Cpu.Arch) !void { | 212 | pub fn writeOperands( |
| | 213 | self: Instruction, |
| | 214 | writer: anytype, |
| | 215 | cie: dwarf.CommonInformationEntry, |
| | 216 | arch: ?std.Target.Cpu.Arch, |
| | 217 | addr_size_bytes: u8, |
| | 218 | endian: std.builtin.Endian, |
| | 219 | ) !void { |
| 202 | switch (self) { | 220 | switch (self) { |
| 203 | inline .advance_loc, .advance_loc1, .advance_loc2, .advance_loc4 => |i| try writer.print("{}", .{ i.operands.delta * cie.code_alignment_factor }), | 221 | inline .advance_loc, .advance_loc1, .advance_loc2, .advance_loc4 => |i| try writer.print("{}", .{i.operands.delta * cie.code_alignment_factor}), |
| 204 | .offset => |i| { | 222 | .offset => |i| { |
| 205 | try abi.writeRegisterName(writer, arch, i.operands.register); | 223 | try abi.writeRegisterName(writer, arch, i.operands.register); |
| 206 | try writer.print(" {}", .{ @intCast(i64, i.operands.offset) * cie.data_alignment_factor }); | 224 | try writer.print(" {}", .{@intCast(i64, i.operands.offset) * cie.data_alignment_factor}); |
| 207 | }, | 225 | }, |
| 208 | .restore => {}, | 226 | .restore => {}, |
| 209 | .nop => {}, | 227 | .nop => {}, |
| ... | @@ -217,14 +235,14 @@ pub const Instruction = union(Opcode) { | ... | @@ -217,14 +235,14 @@ pub const Instruction = union(Opcode) { |
| 217 | .restore_state => {}, | 235 | .restore_state => {}, |
| 218 | .def_cfa => |i| { | 236 | .def_cfa => |i| { |
| 219 | try abi.writeRegisterName(writer, arch, i.operands.register); | 237 | try abi.writeRegisterName(writer, arch, i.operands.register); |
| 220 | try writer.print(" {}", .{ fmtOffset(@intCast(i64, i.operands.offset)) }); | 238 | try writer.print(" {d:<1}", .{@intCast(i64, i.operands.offset)}); |
| 221 | }, | 239 | }, |
| 222 | .def_cfa_register => {}, | 240 | .def_cfa_register => {}, |
| 223 | .def_cfa_offset => |i| { | 241 | .def_cfa_offset => |i| { |
| 224 | try writer.print("{}", .{ fmtOffset(@intCast(i64, i.operands.offset)) }); | 242 | try writer.print("{d:<1}", .{@intCast(i64, i.operands.offset)}); |
| 225 | }, | 243 | }, |
| 226 | .def_cfa_expression => |i| { | 244 | .def_cfa_expression => |i| { |
| 227 | try writer.print("TODO(parse expressions data {x})", .{ std.fmt.fmtSliceHexLower(i.operands.block) }); | 245 | try writeExpression(writer, i.operands.block, arch, addr_size_bytes, endian); |
| 228 | }, | 246 | }, |
| 229 | .expression => {}, | 247 | .expression => {}, |
| 230 | .offset_extended_sf => {}, | 248 | .offset_extended_sf => {}, |
| ... | @@ -235,23 +253,83 @@ pub const Instruction = union(Opcode) { | ... | @@ -235,23 +253,83 @@ pub const Instruction = union(Opcode) { |
| 235 | .val_expression => {}, | 253 | .val_expression => {}, |
| 236 | } | 254 | } |
| 237 | } | 255 | } |
| 238 | | | |
| 239 | }; | 256 | }; |
| 240 | | 257 | |
| | 258 | fn writeExpression( |
| | 259 | writer: anytype, |
| | 260 | block: []const u8, |
| | 261 | arch: ?std.Target.Cpu.Arch, |
| | 262 | addr_size_bytes: u8, |
| | 263 | endian: std.builtin.Endian, |
| | 264 | ) !void { |
| | 265 | var stream = std.io.fixedBufferStream(block); |
| | 266 | |
| | 267 | // Generate a lookup table from opcode value to name |
| | 268 | const opcode_lut_len = 256; |
| | 269 | const opcode_lut: [opcode_lut_len]?[]const u8 = comptime blk: { |
| | 270 | var lut: [opcode_lut_len]?[]const u8 = [_]?[]const u8{null} ** opcode_lut_len; |
| | 271 | for (@typeInfo(dwarf.OP).Struct.decls) |decl| { |
| | 272 | lut[@as(u8, @field(dwarf.OP, decl.name))] = decl.name; |
| | 273 | } |
| 241 | | 274 | |
| 242 | fn formatOffset(data: i64, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | 275 | break :blk lut; |
| 243 | _ = fmt; | 276 | }; |
| 244 | if (data >= 0) try writer.writeByte('+'); | | |
| 245 | return std.fmt.formatInt(data, 10, .lower, options, writer); | | |
| 246 | } | | |
| 247 | | 277 | |
| 248 | fn fmtOffset(offset: i64) std.fmt.Formatter(formatOffset) { | 278 | switch (endian) { |
| 249 | return .{ .data = offset }; | 279 | inline .Little, .Big => |e| { |
| | 280 | switch (addr_size_bytes) { |
| | 281 | inline 2, 4, 8 => |size| { |
| | 282 | const StackMachine = expressions.StackMachine(.{ |
| | 283 | .addr_size = size, |
| | 284 | .endian = e, |
| | 285 | .call_frame_mode = true, |
| | 286 | }); |
| | 287 | |
| | 288 | const reader = stream.reader(); |
| | 289 | while (stream.pos < stream.buffer.len) { |
| | 290 | if (stream.pos > 0) try writer.writeAll(", "); |
| | 291 | |
| | 292 | const opcode = try reader.readByte(); |
| | 293 | if (opcode_lut[opcode]) |opcode_name| { |
| | 294 | try writer.print("DW_OP_{s}", .{opcode_name}); |
| | 295 | } else { |
| | 296 | // TODO: See how llvm-dwarfdump prints these? |
| | 297 | if (opcode >= dwarf.OP.lo_user and opcode <= dwarf.OP.lo_user) { |
| | 298 | try writer.print("<unknown vendor opcode: 0x{x}>", .{opcode}); |
| | 299 | } else { |
| | 300 | try writer.print("<invalid opcode: 0x{x}>", .{opcode}); |
| | 301 | } |
| | 302 | } |
| | 303 | |
| | 304 | if (try StackMachine.readOperand(&stream, opcode)) |value| { |
| | 305 | switch (value) { |
| | 306 | //.generic => |v| try writer.print("{d}", .{v}), |
| | 307 | .generic => {}, // Constant values are implied by the opcode name |
| | 308 | .register => |v| try writer.print(" {}", .{ abi.fmtRegister(v, arch) }), |
| | 309 | .base_register => |v| try writer.print(" {}{d:<1}", .{ abi.fmtRegister(v.base_register, arch), v.offset }), |
| | 310 | else => try writer.print(" TODO({s})", .{@tagName(value)}), |
| | 311 | } |
| | 312 | } |
| | 313 | } |
| | 314 | }, |
| | 315 | else => return error.InvalidAddrSize, |
| | 316 | } |
| | 317 | }, |
| | 318 | } |
| 250 | } | 319 | } |
| 251 | | 320 | |
| | 321 | // fn formatOffset(data: i64, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { |
| | 322 | // _ = fmt; |
| | 323 | // if (data >= 0) try writer.writeByte('+'); |
| | 324 | // return std.fmt.formatInt(data, 10, .lower, options, writer); |
| | 325 | // } |
| | 326 | |
| | 327 | // fn fmtOffset(offset: i64) std.fmt.Formatter(formatOffset) { |
| | 328 | // return .{ .data = offset }; |
| | 329 | // } |
| | 330 | |
| 252 | /// See section 6.4.1 of the DWARF5 specification | 331 | /// See section 6.4.1 of the DWARF5 specification |
| 253 | pub const VirtualMachine = struct { | 332 | pub const VirtualMachine = struct { |
| 254 | | | |
| 255 | const RegisterRule = union(enum) { | 333 | const RegisterRule = union(enum) { |
| 256 | undefined: void, | 334 | undefined: void, |
| 257 | same_value: void, | 335 | same_value: void, |
| ... | @@ -263,11 +341,18 @@ pub const VirtualMachine = struct { | ... | @@ -263,11 +341,18 @@ pub const VirtualMachine = struct { |
| 263 | architectural: void, | 341 | architectural: void, |
| 264 | }; | 342 | }; |
| 265 | | 343 | |
| 266 | const Column = struct { | 344 | pub const Column = struct { |
| 267 | register: u8 = undefined, | 345 | register: u8 = undefined, |
| 268 | rule: RegisterRule = .{ .undefined = {} }, | 346 | rule: RegisterRule = .{ .undefined = {} }, |
| 269 | | 347 | |
| 270 | pub fn writeRule(self: Column, writer: anytype, is_cfa: bool, arch: ?std.Target.Cpu.Arch) !void { | 348 | pub fn writeRule( |
| | 349 | self: Column, |
| | 350 | writer: anytype, |
| | 351 | is_cfa: bool, |
| | 352 | arch: ?std.Target.Cpu.Arch, |
| | 353 | addr_size_bytes: u8, |
| | 354 | endian: std.builtin.Endian, |
| | 355 | ) !void { |
| 271 | if (is_cfa) { | 356 | if (is_cfa) { |
| 272 | try writer.writeAll("CFA"); | 357 | try writer.writeAll("CFA"); |
| 273 | } else { | 358 | } else { |
| ... | @@ -281,48 +366,54 @@ pub const VirtualMachine = struct { | ... | @@ -281,48 +366,54 @@ pub const VirtualMachine = struct { |
| 281 | .offset => |offset| { | 366 | .offset => |offset| { |
| 282 | if (is_cfa) { | 367 | if (is_cfa) { |
| 283 | try abi.writeRegisterName(writer, arch, self.register); | 368 | try abi.writeRegisterName(writer, arch, self.register); |
| 284 | try writer.print("{}", .{ fmtOffset(offset) }); | 369 | try writer.print("{d:<1}", .{offset}); |
| 285 | } else { | 370 | } else { |
| 286 | try writer.print("[CFA{}]", .{ fmtOffset(offset) }); | 371 | try writer.print("[CFA{d:<1}]", .{offset}); |
| 287 | } | 372 | } |
| 288 | }, | 373 | }, |
| 289 | .val_offset => |offset| { | 374 | .val_offset => |offset| { |
| 290 | if (is_cfa) { | 375 | if (is_cfa) { |
| 291 | try abi.writeRegisterName(writer, arch, self.register); | 376 | try abi.writeRegisterName(writer, arch, self.register); |
| 292 | try writer.print("{}", .{ fmtOffset(offset) }); | 377 | try writer.print("{d:<1}", .{offset}); |
| 293 | } else { | 378 | } else { |
| 294 | try writer.print("CFA{}", .{ fmtOffset(offset) }); | 379 | try writer.print("CFA{d:<1}", .{offset}); |
| 295 | } | 380 | } |
| 296 | }, | 381 | }, |
| 297 | .register => |register| try abi.writeRegisterName(writer, arch, register), | 382 | .register => |register| try abi.writeRegisterName(writer, arch, register), |
| 298 | .expression => try writer.writeAll("TODO(expression)"), | 383 | .expression => |expression| try writeExpression(writer, expression, arch, addr_size_bytes, endian), |
| 299 | .val_expression => try writer.writeAll("TODO(val_expression)"), | 384 | .val_expression => try writer.writeAll("TODO(val_expression)"), |
| 300 | .architectural => try writer.writeAll("TODO(architectural)"), | 385 | .architectural => try writer.writeAll("TODO(architectural)"), |
| 301 | } | 386 | } |
| 302 | } | 387 | } |
| 303 | }; | 388 | }; |
| 304 | | 389 | |
| | 390 | /// Each row contains unwinding rules for a set of registers at a specific location in the program. |
| 305 | pub const Row = struct { | 391 | pub const Row = struct { |
| 306 | /// Offset from pc_begin | 392 | /// Offset from pc_begin |
| 307 | offset: u64 = 0, | 393 | offset: u64 = 0, |
| | 394 | /// Special-case column that defines the CFA (Canonical Frame Address) rule. |
| | 395 | /// The register field of this column defines the register that CFA is derived |
| | 396 | /// from, while other columns define registers in terms of the CFA. |
| 308 | cfa: Column = .{}, | 397 | cfa: Column = .{}, |
| 309 | /// Index into `columns` of the first column in this row | 398 | /// Index into `columns` of the first column in this row. |
| 310 | columns_start: usize = undefined, | 399 | columns_start: usize = undefined, |
| 311 | columns_len: u8 = 0, | 400 | columns_len: u8 = 0, |
| 312 | }; | 401 | }; |
| 313 | | 402 | |
| 314 | rows: std.ArrayListUnmanaged(Row) = .{}, | | |
| 315 | columns: std.ArrayListUnmanaged(Column) = .{}, | 403 | columns: std.ArrayListUnmanaged(Column) = .{}, |
| | 404 | row_stack: std.ArrayListUnmanaged(Row) = .{}, |
| 316 | current_row: Row = .{}, | 405 | current_row: Row = .{}, |
| 317 | | 406 | |
| | 407 | // TODO: Add stack machine stack |
| | 408 | |
| 318 | pub fn reset(self: *VirtualMachine) void { | 409 | pub fn reset(self: *VirtualMachine) void { |
| 319 | self.rows.clearRetainingCapacity(); | 410 | self.row_stack.clearRetainingCapacity(); |
| 320 | self.columns.clearRetainingCapacity(); | 411 | self.columns.clearRetainingCapacity(); |
| 321 | self.current_row = .{}; | 412 | self.current_row = .{}; |
| 322 | } | 413 | } |
| 323 | | 414 | |
| 324 | pub fn deinit(self: *VirtualMachine, allocator: std.mem.Allocator) void { | 415 | pub fn deinit(self: *VirtualMachine, allocator: std.mem.Allocator) void { |
| 325 | self.rows.deinit(allocator); | 416 | self.row_stack.deinit(allocator); |
| 326 | self.columns.deinit(allocator); | 417 | self.columns.deinit(allocator); |
| 327 | self.* = undefined; | 418 | self.* = undefined; |
| 328 | } | 419 | } |
| ... | @@ -366,8 +457,20 @@ pub const VirtualMachine = struct { | ... | @@ -366,8 +457,20 @@ pub const VirtualMachine = struct { |
| 366 | .undefined => {}, | 457 | .undefined => {}, |
| 367 | .same_value => {}, | 458 | .same_value => {}, |
| 368 | .register => {}, | 459 | .register => {}, |
| 369 | .remember_state => {}, | 460 | .remember_state => { |
| 370 | .restore_state => {}, | 461 | |
| | 462 | // TODO: The row stack only actually needs the column information |
| | 463 | // TODO: Also it needs to copy the columns because changes can edit the referenced columns |
| | 464 | // TODO: This function could push the column range onto the stack, the copy the columns and update current row |
| | 465 | |
| | 466 | try self.row_stack.append(allocator, self.current_row); |
| | 467 | }, |
| | 468 | .restore_state => { |
| | 469 | if (self.row_stack.items.len == 0) return error.InvalidOperation; |
| | 470 | const row = self.row_stack.pop(); |
| | 471 | self.current_row.columns_len = row.columns_len; |
| | 472 | self.current_row.columns_start = row.columns_start; |
| | 473 | }, |
| 371 | .def_cfa => |i| { | 474 | .def_cfa => |i| { |
| 372 | self.current_row.cfa = .{ | 475 | self.current_row.cfa = .{ |
| 373 | .register = i.operands.register, | 476 | .register = i.operands.register, |
| ... | @@ -376,11 +479,14 @@ pub const VirtualMachine = struct { | ... | @@ -376,11 +479,14 @@ pub const VirtualMachine = struct { |
| 376 | }, | 479 | }, |
| 377 | .def_cfa_register => {}, | 480 | .def_cfa_register => {}, |
| 378 | .def_cfa_offset => |i| { | 481 | .def_cfa_offset => |i| { |
| | 482 | self.current_row.cfa.rule = .{ .offset = @intCast(i64, i.operands.offset) }; |
| | 483 | }, |
| | 484 | .def_cfa_expression => |i| { |
| | 485 | self.current_row.cfa.register = undefined; |
| 379 | self.current_row.cfa.rule = .{ | 486 | self.current_row.cfa.rule = .{ |
| 380 | .offset = @intCast(i64, i.operands.offset) | 487 | .expression = i.operands.block, |
| 381 | }; | 488 | }; |
| 382 | }, | 489 | }, |
| 383 | .def_cfa_expression => {}, | | |
| 384 | .expression => {}, | 490 | .expression => {}, |
| 385 | .offset_extended_sf => {}, | 491 | .offset_extended_sf => {}, |
| 386 | .def_cfa_sf => {}, | 492 | .def_cfa_sf => {}, |
| ... | @@ -390,5 +496,4 @@ pub const VirtualMachine = struct { | ... | @@ -390,5 +496,4 @@ pub const VirtualMachine = struct { |
| 390 | .val_expression => {}, | 496 | .val_expression => {}, |
| 391 | } | 497 | } |
| 392 | } | 498 | } |
| 393 | | | |
| 394 | }; | 499 | }; |