| ... | ... | @@ -33,7 +33,7 @@ pub const ExpressionOptions = struct { |
| 33 | 33 | addr_size: u8 = @sizeOf(usize), |
| 34 | 34 | |
| 35 | 35 | /// Endianess of the target architecture |
| 36 | | endian: std.builtin.Endian = .Little, |
| 36 | endian: std.builtin.Endian = builtin.target.cpu.arch.endian(), |
| 37 | 37 | |
| 38 | 38 | /// Restrict the stack machine to a subset of opcodes used in call frame instructions |
| 39 | 39 | call_frame_context: bool = false, |
| ... | ... | @@ -272,7 +272,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { |
| 272 | 272 | return self.stack.items[self.stack.items.len - 1]; |
| 273 | 273 | } |
| 274 | 274 | |
| 275 | | /// Reads an opcode and its operands from the stream and executes it |
| 275 | /// Reads an opcode and its operands from `stream`, then executes it |
| 276 | 276 | pub fn step( |
| 277 | 277 | self: *Self, |
| 278 | 278 | stream: *std.io.FixedBufferStream([]const u8), |
| ... | ... | @@ -607,7 +607,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { |
| 607 | 607 | const a_int: isize = @bitCast(a.asIntegral() catch unreachable); |
| 608 | 608 | const b_int: isize = @bitCast(b.asIntegral() catch unreachable); |
| 609 | 609 | const result = @intFromBool(switch (opcode) { |
| 610 | | OP.le => b_int < a_int, |
| 610 | OP.le => b_int <= a_int, |
| 611 | 611 | OP.ge => b_int >= a_int, |
| 612 | 612 | OP.eq => b_int == a_int, |
| 613 | 613 | OP.lt => b_int < a_int, |
| ... | ... | @@ -635,7 +635,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { |
| 635 | 635 | try std.math.add(isize, @as(isize, @intCast(stream.pos)), branch_offset), |
| 636 | 636 | ) orelse return error.InvalidExpression; |
| 637 | 637 | |
| 638 | | if (new_pos < 0 or new_pos >= stream.buffer.len) return error.InvalidExpression; |
| 638 | if (new_pos < 0 or new_pos > stream.buffer.len) return error.InvalidExpression; |
| 639 | 639 | stream.pos = new_pos; |
| 640 | 640 | } |
| 641 | 641 | }, |
| ... | ... | @@ -657,12 +657,16 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { |
| 657 | 657 | OP.convert => { |
| 658 | 658 | if (self.stack.items.len == 0) return error.InvalidExpression; |
| 659 | 659 | const type_offset = (try readOperand(stream, opcode)).?.generic; |
| 660 | | _ = type_offset; |
| 661 | 660 | |
| 662 | | // TODO: Load the DW_TAG_base_type entry in context.compile_unit, find a conversion operator |
| 663 | | // from the old type to the new type, run it. |
| 664 | | |
| 665 | | return error.UnimplementedTypeConversion; |
| 661 | // TODO: Load the DW_TAG_base_type entries in context.compile_unit and verify both types are the same size |
| 662 | const value = self.stack.items[self.stack.items.len - 1]; |
| 663 | if (type_offset == 0) { |
| 664 | self.stack.items[self.stack.items.len - 1] = .{ .generic = try value.asIntegral() }; |
| 665 | } else { |
| 666 | // TODO: Load the DW_TAG_base_type entry in context.compile_unit, find a conversion operator |
| 667 | // from the old type to the new type, run it. |
| 668 | return error.UnimplementedTypeConversion; |
| 669 | } |
| 666 | 670 | }, |
| 667 | 671 | OP.reinterpret => { |
| 668 | 672 | if (self.stack.items.len == 0) return error.InvalidExpression; |
| ... | ... | @@ -1373,4 +1377,66 @@ test "DWARF expressions" { |
| 1373 | 1377 | _ = try stack_machine.run(program.items, allocator, context, null); |
| 1374 | 1378 | try testing.expectEqual(@as(usize, 0x0ff0), stack_machine.stack.popOrNull().?.generic); |
| 1375 | 1379 | } |
| 1380 | |
| 1381 | |
| 1382 | // Control Flow Operations |
| 1383 | { |
| 1384 | var context = ExpressionContext{}; |
| 1385 | const expected = .{ |
| 1386 | .{ OP.le, 1, 1, 0 }, |
| 1387 | .{ OP.ge, 1, 0, 1 }, |
| 1388 | .{ OP.eq, 1, 0, 0 }, |
| 1389 | .{ OP.lt, 0, 1, 0 }, |
| 1390 | .{ OP.gt, 0, 0, 1 }, |
| 1391 | .{ OP.ne, 0, 1, 1 }, |
| 1392 | }; |
| 1393 | |
| 1394 | inline for (expected) |e| { |
| 1395 | stack_machine.reset(); |
| 1396 | program.clearRetainingCapacity(); |
| 1397 | |
| 1398 | try b.writeConst(writer, u16, 0); |
| 1399 | try b.writeConst(writer, u16, 0); |
| 1400 | try b.writeOpcode(writer, e[0]); |
| 1401 | try b.writeConst(writer, u16, 0); |
| 1402 | try b.writeConst(writer, u16, 1); |
| 1403 | try b.writeOpcode(writer, e[0]); |
| 1404 | try b.writeConst(writer, u16, 1); |
| 1405 | try b.writeConst(writer, u16, 0); |
| 1406 | try b.writeOpcode(writer, e[0]); |
| 1407 | _ = try stack_machine.run(program.items, allocator, context, null); |
| 1408 | try testing.expectEqual(@as(usize, e[3]), stack_machine.stack.popOrNull().?.generic); |
| 1409 | try testing.expectEqual(@as(usize, e[2]), stack_machine.stack.popOrNull().?.generic); |
| 1410 | try testing.expectEqual(@as(usize, e[1]), stack_machine.stack.popOrNull().?.generic); |
| 1411 | } |
| 1412 | |
| 1413 | stack_machine.reset(); |
| 1414 | program.clearRetainingCapacity(); |
| 1415 | try b.writeLiteral(writer, 2); |
| 1416 | try b.writeSkip(writer, 1); |
| 1417 | try b.writeLiteral(writer, 3); |
| 1418 | _ = try stack_machine.run(program.items, allocator, context, null); |
| 1419 | try testing.expectEqual(@as(usize, 2), stack_machine.stack.popOrNull().?.generic); |
| 1420 | |
| 1421 | |
| 1422 | stack_machine.reset(); |
| 1423 | program.clearRetainingCapacity(); |
| 1424 | try b.writeLiteral(writer, 2); |
| 1425 | try b.writeBra(writer, 1); |
| 1426 | try b.writeLiteral(writer, 3); |
| 1427 | try b.writeLiteral(writer, 0); |
| 1428 | try b.writeBra(writer, 1); |
| 1429 | try b.writeLiteral(writer, 4); |
| 1430 | try b.writeLiteral(writer, 5); |
| 1431 | _ = try stack_machine.run(program.items, allocator, context, null); |
| 1432 | try testing.expectEqual(@as(usize, 5), stack_machine.stack.popOrNull().?.generic); |
| 1433 | try testing.expectEqual(@as(usize, 4), stack_machine.stack.popOrNull().?.generic); |
| 1434 | try testing.expect(stack_machine.stack.popOrNull() == null); |
| 1435 | |
| 1436 | // TODO: Test call2, call4, call_ref once implemented |
| 1437 | |
| 1438 | } |
| 1439 | |
| 1440 | |
| 1376 | 1441 | } |
| 1442 | |