| ... | @@ -33,7 +33,7 @@ pub const ExpressionOptions = struct { | ... | @@ -33,7 +33,7 @@ pub const ExpressionOptions = struct { |
| 33 | addr_size: u8 = @sizeOf(usize), | 33 | addr_size: u8 = @sizeOf(usize), |
| 34 | | 34 | |
| 35 | /// Endianess of the target architecture | 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 | /// Restrict the stack machine to a subset of opcodes used in call frame instructions | 38 | /// Restrict the stack machine to a subset of opcodes used in call frame instructions |
| 39 | call_frame_context: bool = false, | 39 | call_frame_context: bool = false, |
| ... | @@ -272,7 +272,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { | ... | @@ -272,7 +272,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { |
| 272 | return self.stack.items[self.stack.items.len - 1]; | 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 | pub fn step( | 276 | pub fn step( |
| 277 | self: *Self, | 277 | self: *Self, |
| 278 | stream: *std.io.FixedBufferStream([]const u8), | 278 | stream: *std.io.FixedBufferStream([]const u8), |
| ... | @@ -607,7 +607,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { | ... | @@ -607,7 +607,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { |
| 607 | const a_int: isize = @bitCast(a.asIntegral() catch unreachable); | 607 | const a_int: isize = @bitCast(a.asIntegral() catch unreachable); |
| 608 | const b_int: isize = @bitCast(b.asIntegral() catch unreachable); | 608 | const b_int: isize = @bitCast(b.asIntegral() catch unreachable); |
| 609 | const result = @intFromBool(switch (opcode) { | 609 | const result = @intFromBool(switch (opcode) { |
| 610 | OP.le => b_int < a_int, | 610 | OP.le => b_int <= a_int, |
| 611 | OP.ge => b_int >= a_int, | 611 | OP.ge => b_int >= a_int, |
| 612 | OP.eq => b_int == a_int, | 612 | OP.eq => b_int == a_int, |
| 613 | OP.lt => b_int < a_int, | 613 | OP.lt => b_int < a_int, |
| ... | @@ -635,7 +635,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { | ... | @@ -635,7 +635,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { |
| 635 | try std.math.add(isize, @as(isize, @intCast(stream.pos)), branch_offset), | 635 | try std.math.add(isize, @as(isize, @intCast(stream.pos)), branch_offset), |
| 636 | ) orelse return error.InvalidExpression; | 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 | stream.pos = new_pos; | 639 | stream.pos = new_pos; |
| 640 | } | 640 | } |
| 641 | }, | 641 | }, |
| ... | @@ -657,12 +657,16 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { | ... | @@ -657,12 +657,16 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { |
| 657 | OP.convert => { | 657 | OP.convert => { |
| 658 | if (self.stack.items.len == 0) return error.InvalidExpression; | 658 | if (self.stack.items.len == 0) return error.InvalidExpression; |
| 659 | const type_offset = (try readOperand(stream, opcode)).?.generic; | 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 | 661 | // TODO: Load the DW_TAG_base_type entries in context.compile_unit and verify both types are the same size |
| 663 | // from the old type to the new type, run it. | 662 | const value = self.stack.items[self.stack.items.len - 1]; |
| 664 | | 663 | if (type_offset == 0) { |
| 665 | return error.UnimplementedTypeConversion; | 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 | OP.reinterpret => { | 671 | OP.reinterpret => { |
| 668 | if (self.stack.items.len == 0) return error.InvalidExpression; | 672 | if (self.stack.items.len == 0) return error.InvalidExpression; |
| ... | @@ -1373,4 +1377,66 @@ test "DWARF expressions" { | ... | @@ -1373,4 +1377,66 @@ test "DWARF expressions" { |
| 1373 | _ = try stack_machine.run(program.items, allocator, context, null); | 1377 | _ = try stack_machine.run(program.items, allocator, context, null); |
| 1374 | try testing.expectEqual(@as(usize, 0x0ff0), stack_machine.stack.popOrNull().?.generic); | 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 | |